2012-02-28 7 views
12

야외 사용을위한 사용자 정의 '고 대비'테마가있는 응용 프로그램을 빌드하면 런타임 중에 켜기/끄기를 전환 할 수 있습니다. 이것은 메뉴 항목의 사용 스타일을 지정하지 않는 경우는 잘 작동Style BasedOn 용 DynamicResource

<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> 

... 병합 아래처럼 스타일이 포함 된 리소스 사전을 유엔 - 병합하여 잘 작동합니다. 이것은 Styles없이 ItemsSource 생성 된 자식을 바인딩 할 수있는 방법이 없기 때문에 현실적이지 않습니다. 예를 들어 : 내 BasedOn이 런타임에 변경됩니다 수 있기 때문에 StackOverflow에 다른 모든 포스트 방금이 작업을 수행 할 필요가 말한다

<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> 

...

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

을하지만 내 상황이 작동하지 않습니다 물론 BasedOn 속성에는 DynamicResource 확장을 사용할 수 없습니다. 내 응용 프로그램에서이 작업을 수행하면 컨트롤을로드 할 때 스타일이 달라 붙는 대신 다른 모든 컨트롤이 다시로드되지 않고 올바르게 전환되는 컨트롤로 연결됩니다.

그래서 내 질문 ...

가 BasedOn 근무 DynamicResource 확장을 얻을 수있는 방법이 있나요 또는 다른 방법이있다는/나는이 작동하도록하기 위해 구현 해킹에서?

답변

7

마지막으로 파악 Style.BasedOn에 대한 DynamicResouce위한 솔루션 AttachedDependencyProperty를 사용하여 :

나는 비슷한하지만 이런 복잡을한다. 여기

<!-- 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을 설정하는 수정 버전 ... 여기

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를 변경하도록 변경 될 수 있음)이고, 여기서 예는 대신 다른 게시물에 대한 내 대답 : Setting a local implicit style different from theme-style/alternative to BasedOn DynamicResource

+0

기본 스타일을 '복사'하는 쉬운 방법이 있습니다. 나는 이것을 새로운 대답으로 추가했다. – aliceraunsbaek

1

스타일은 UIElement.Resources 태그에 있어야합니다. 이것은 동적으로 지워지고 다시 채울 수 있습니다.

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에서 무엇을 의미하는지 모르겠습니다. 태그를 제거하십시오. – NtscCobalt

+0

에 스타일을 명시 적으로 설정하는 대신 UIElement.Resources에 스타일 배치를 테스트했지만 동일한 효과가 있고 을 더 쉽게 읽을 수 있습니다. – NtscCobalt

3

나는 약간의 imp가 있습니다. NtscCobalts에 대한 답변 :

#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 

새 스타일을 만들 때 기본 스타일을 설정할 수 있습니다. 이렇게하면 기본 스타일의 기본 스타일이 자동으로 계층 구조에 포함됩니다.

관련 문제