2012-02-28 14 views
12

ऐसे एप्लिकेशन का निर्माण करना जिसमें बाहरी उपयोग के लिए कस्टम 'हाई कंट्रास्ट' थीम है जिसे रनटाइम के दौरान चालू और बंद किया जा सकता है। यह विलय और एक संसाधन शब्दकोश कि नीचे की तरह शैलियों शामिल अन-मर्ज करके ठीक काम करता है ...स्टाइल आधारित के लिए डायनामिक रिसोर्स

<Style x:Key="{x:Type MenuItem}" TargetType="{x:Type MenuItem}"> 
    <Setter Property="OverridesDefaultStyle" Value="true"/> 
    <Setter Property="FocusVisualStyle" Value="{x:Null}"/> 
    <Setter Property="Template" Value="{StaticResource Theme_MenuItemTemplate}"/> 
</Style> 

यह महान काम करता है जब एक MENUITEM के उपयोग एक शैली निर्दिष्ट नहीं है। हालांकि यह कई यथार्थियों के लिए यथार्थवादी नहीं है क्योंकि स्टाइल के बिना आइटम्ससोर्स जेनरेट किए गए बच्चों को बांधने का कोई तरीका नहीं है। उदाहरण के लिए:

<ContextMenu.ItemContainerStyle> 
    <Style TargetType="MenuItem"> 
     <Setter Property="Header" Value="{Binding Path=Name}"/> 
     <Setter Property="IsCheckable" Value="True"/> 
     <Setter Property="IsChecked" Value="{Binding Path=Checked}"/> 
     <EventSetter Event="Checked" Handler="HistoryItem_Checked"/> 
    </Style> 
</ContextMenu.ItemContainerStyle> 

StackOverflow पर हर अन्य पोस्ट का कहना है कि आप सिर्फ यह करने की आवश्यकता ...

<Style TargetType="MenuItem" BasedOn="{StaticResource {x:Type MenuItem}}"> 
    <!-- Your overrides --> 
</Style> 

लेकिन यह मेरी स्थिति के लिए काम नहीं करता क्योंकि मेरे basedon और कार्यावधि में बदल जाएगा कर सकते हैं (और निश्चित रूप से आप BasedOn प्रॉपर्टी पर डायनामिक रिसोर्स एक्सटेंशन का उपयोग नहीं कर सकते हैं)। मेरे आवेदन में ऐसा करने से वर्तमान में नियंत्रण होता है जो नियंत्रण को लोड करते समय अपनी शैली के साथ अटक जाते हुए ओवरराइड करते हैं जबकि हर दूसरे नियंत्रण को पुनः लोड किए बिना सही ढंग से स्विच किया जाता है।

तो मेरे सवाल ...

वहाँ एक रास्ता basedon के लिए काम DynamicResource विस्तार पाने के लिए है या किसी अन्य विधि है/मैं इस काम करने के लिए प्राप्त करने के लिए लागू कर सकते हैं हैक?

उत्तर

7

अंत में पता लगा Style.BasedOn के लिए एक DynamicResouce के लिए एक समाधान एक AttachedDependencyProperty का उपयोग कर:

मैं इस तरह जटिल नहीं के रूप में कुछ इसी तरह, लेकिन है।

यहाँ ItemsControl.ItemContainerStyle के लिए ठीक

public class DynamicContainerStyle 
{ 
    public static Style GetBaseStyle(DependencyObject obj) 
    { 
     return (Style)obj.GetValue(BaseStyleProperty); 
    } 

    public static void SetBaseStyle(DependencyObject obj, Style value) 
    { 
     obj.SetValue(BaseStyleProperty, value); 
    } 

    // Using a DependencyProperty as the backing store for BaseStyle. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty BaseStyleProperty = 
     DependencyProperty.RegisterAttached("BaseStyle", typeof(Style), typeof(DynamicContainerStyle), new UIPropertyMetadata(DynamicContainerStyle.StylesChanged)); 

    public static Style GetDerivedStyle(DependencyObject obj) 
    { 
     return (Style)obj.GetValue(DerivedStyleProperty); 
    } 

    public static void SetDerivedStyle(DependencyObject obj, Style value) 
    { 
     obj.SetValue(DerivedStyleProperty, value); 
    } 

    // Using a DependencyProperty as the backing store for DerivedStyle. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty DerivedStyleProperty = 
     DependencyProperty.RegisterAttached("DerivedStyle", typeof(Style), typeof(DynamicContainerStyle), new UIPropertyMetadata(DynamicContainerStyle.StylesChanged)); 

    private static void StylesChanged(DependencyObject target, DependencyPropertyChangedEventArgs e) 
    { 
     if (!typeof(System.Windows.Controls.ItemsControl).IsAssignableFrom(target.GetType())) 
      throw new InvalidCastException("Target must be ItemsControl"); 

     var Element = (System.Windows.Controls.ItemsControl)target; 

     var Styles = new List<Style>(); 

     var BaseStyle = GetBaseStyle(target); 

     if (BaseStyle != null) 
      Styles.Add(BaseStyle); 

     var DerivedStyle = GetDerivedStyle(target); 

     if (DerivedStyle != null) 
      Styles.Add(DerivedStyle); 

     Element.ItemContainerStyle = MergeStyles(Styles); 
    } 

    private static Style MergeStyles(ICollection<Style> Styles) 
    { 
     var NewStyle = new Style(); 

     foreach (var Style in Styles) 
     { 
      foreach (var Setter in Style.Setters) 
       NewStyle.Setters.Add(Setter); 

      foreach (var Trigger in Style.Triggers) 
       NewStyle.Triggers.Add(Trigger); 
     } 

     return NewStyle; 
    } 
} 

(आसानी से FrameworkElement.Style बदलने के लिए संशोधित किया जा सकता है) है और यहाँ एक उदाहरण है ...

<!-- xmlns:ap points to the namespace where DynamicContainerStyle class lives --> 
<MenuItem Header="Recent" 
    ItemsSource="{Binding Path=RecentFiles}" 
    IsEnabled="{Binding RelativeSource={RelativeSource Self}, Path=HasItems}" 
    ap:DynamicContainerStyle.BaseStyle="{DynamicResource {x:Type MenuItem}}"> 
    <ap:DynamicContainerStyle.DerivedStyle> 
     <Style TargetType="MenuItem"> 
      <EventSetter Event="Click" Handler="RecentFile_Clicked"/> 
     </Style> 
    </ap:DynamicContainerStyle.DerivedStyle> 
    <MenuItem.ItemTemplate> 
     <DataTemplate> 
      <TextBlock Text="{Binding}"/> 
     </DataTemplate> 
    </MenuItem.ItemTemplate> 
</MenuItem> 

यहाँ एक संशोधित संस्करण है कि FrameworkElement.Style सेट है इसके बजाय मेरे उत्तर में एक अन्य पोस्ट में: Setting a local implicit style different from theme-style/alternative to BasedOn DynamicResource

+0

आधार शैलियों की प्रतिलिपि बनाने का एक आसान तरीका है। मैंने इसे एक नए जवाब में जोड़ा। – aliceraunsbaek

1

आपकी शैलियों को UIElement में होना चाहिए। स्रोत टैग। इसे गतिशील रूप से साफ़ और पुनर्निर्मित किया जा सकता है।

MobileApp.Get().Resources.MergedDictionaries.Clear(); 

Uri uri = new Uri("/Resources/DayModeButton.xaml", UriKind.Relative); 
ResourceDictionary resDict = Application.LoadComponent(uri) as ResourceDictionary; 

resDict["SelectedColor"] = selectedColor; //change an attribute of resdict 

MobileApp.Get().Resources.MergedDictionaries.Add(resDict); 
+0

यह संसाधनों के शब्दकोशों को विलय और अनर्जित करने के लिए मैं काफी कुछ करता हूं। मुझे यकीन नहीं है कि UIElement.Resoruces टैग का मतलब क्या है। – NtscCobalt

+0

मैंने शैली को UIElement में रखने का परीक्षण किया है। में शैली को स्पष्ट रूप से सेट करने के बजाय स्रोत। लेकिन इसका एक ही प्रभाव है और मुझे पढ़ने के लिए आसान उपयोग करना पड़ता है। – NtscCobalt

3

मेरे पास थोड़ा सा आवेग है NtscCobalts के लिए rovement का जवाब:

#region Type-specific function (FrameworkElement) 
    private static void StylesChanged(DependencyObject target, DependencyPropertyChangedEventArgs e) 
    { 
     var mergedStyles = GetMergedStyles<FrameworkElement>(target, GetBaseStyle(target), GetDerivedStyle(target)); // NOTE: change type on copy 

     var element = (FrameworkElement)target; // NOTE: change type on copy 

     element.Style = mergedStyles; 
    } 
    #endregion Type-specific function (FrameworkElement) 


    #region Reused-function 
    public static Style GetMergedStyles<T>(DependencyObject target, Style baseStyle, Style derivedStyle) where T : DependencyObject 
    { 
     if (!(target is T)) throw new InvalidCastException("Target must be " + typeof(T)); 

     if (derivedStyle == null) return baseStyle; 
     if (baseStyle == null) return derivedStyle; 

     var newStyle = new Style { BasedOn = baseStyle, TargetType = derivedStyle.TargetType }; 
     foreach (var setter in derivedStyle.Setters) newStyle.Setters.Add(setter); 
     foreach (var trigger in derivedStyle.Triggers) newStyle.Triggers.Add(trigger); 
     return newStyle; 

    } 
    #endregion Reused-function 

तुम देखो, यह संभव है जब एक नई शैली बनाने के लिए बस, आधार शैली स्थापित करने के लिए। इस तरह आधार शैली से आधार शैलियों स्वचालित रूप से पदानुक्रम में हैं।

संबंधित मुद्दे