2017-08-21 37 views
0

我有一個使用模板方法來設計我的用戶控件的想法。嘗試將資源模板綁定到用戶控件

這是一個自定義菜單控件。它目前作爲一個listview實現。

我想有不同風格的我的用戶控件,取決於它在我的應用程序中的使用位置。應用程序將有一個頂部菜單,右側菜單和底部菜單,至少這是現在的想法。我想爲所有菜單使用相同的用戶控件,但我也想對它們進行不同的設計,而不使用不同版本的用戶控件。

所以我的方法是在Resource/Style文件中定義不同的ControlTemplates。這些ControlTemplates用在主應用程序xaml中,並綁定在menucontainer用戶控件的SelectedTemplate依賴項屬性上。

完整的用戶控制代碼如下。這是場SelectedTemplate是準備在這裏:

<UserControl x:Class="MyApp.Views.Menu.CustomMenuContainer" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:viewModels="clr-namespace:MyApp.Client.ViewModels" 
     xmlns:local="clr-namespace:MyApp.Client.Views" 
     xmlns:commongui="clr-namespace:MyApp.CommonGui;assembly=MyApp.CommonGui" 
     xmlns:menu="clr-namespace:MyApp.Client.ViewModels.Menu" 
     xmlns:webControls="clr-namespace:System.Web.UI.WebControls;assembly=System.Web" 
     mc:Ignorable="d" 

     d:DesignHeight="100" d:DesignWidth="1200"> 
<Grid> 

    <ListView Background="Transparent" 
       BorderBrush="Black" 
       BorderThickness="2" 
       x:Name="MenuList" 
       VerticalAlignment="Stretch" 
       HorizontalAlignment="Stretch" 
       ItemsSource="{Binding Path=MenuItems}" 
       SelectionChanged="MenuList_OnSelectionChanged" 
       SelectedItem="{Binding Path=SelectedItem}" 
       SelectionMode="Single" > 
     <ListView.ItemsPanel> 
      <ItemsPanelTemplate x:Name="MenuPanelTemplate"> 
       <UniformGrid IsItemsHost="True" x:Name="MenuPanel"> 
       </UniformGrid> 
      </ItemsPanelTemplate> 
     </ListView.ItemsPanel> 

     <ListView.Resources> 
      <Style TargetType="ListViewItem" x:Name="MenuItemStyle"> 
       <Style.Triggers> 
        <Trigger Property="IsSelected" Value="True"> 
         <Setter Property="Background" Value="DarkSeaGreen" /> 
         <Setter Property="Template" Value="{Binding SelectedTemplate}" /> 
        </Trigger>      
       </Style.Triggers> 
      </Style> 
     </ListView.Resources> 
    </ListView> 
</Grid> 

SelectedTemplate是用戶控件依賴項屬性:

public static readonly DependencyProperty SelectedTemplateProperty = DependencyProperty.Register(
     "SelectedTemplate", typeof(ControlTemplate), typeof(MenuContainer), new PropertyMetadata(default(ControlTemplate))); 

public ControlTemplate SelectedTemplate { 
    get { return (ControlTemplate)GetValue(SelectedTemplateProperty); } 
    set { SetValue(SelectedTemplateProperty, value); } 
} 

我添加了一個SelectedTemplateChanged的方法來控制時,會發生什麼模板更改:

構造函數中:

DependencyPropertyDescriptor.FromProperty(SelectedTemplateProperty, GetType()).AddValueChanged(this, SelectedTemplateChanged); 

然後執行。我知道我們在模板設置在用戶控件的綁定中時輸入了這段代碼,但我無法弄清楚如何將模板應用到listview selecteditem。

private void SelectedTemplateChanged(object sender, EventArgs e) 
{ 
    //How to access and set the template of the ListView (named MenuList in the xaml) selected item from 
    //code behind? 

    //pseudocode follows: 
    //Find the resources of MenuList 
    //find trigger for isSelected 
    //apply the SelectedTemplate on a setter of the IsSelected trigger... 
} 

以下是主窗口中用戶控件的用法。

我結合從資源文件中的不同CONTROLTEMPLATES(見下文),以每個MENU1的SelectedTemplate:MenuContainer中控制

<Window x:Class="MyApp.Client.Views.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:views="clr-namespace:MyApp.Client.Views" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:viewModels="clr-namespace:MyApp.Client.ViewModels" 
    xmlns:menu1="clr-namespace:MyApp.Client.Views.Menu" 
    xmlns:menu="clr-namespace:MyApp.Client.ViewModels.Menu" 
    mc:Ignorable="d" 
    d:DataContext="{d:DesignInstance viewModels:MyAppViewModel, IsDesignTimeCreatable=True}" 
    Title="MainWindow" Height="800" Width="1200"> 
<Grid> 

    <Grid.RowDefinitions> 
     <RowDefinition Height="{Binding MenuViewModel.TopMenuHeigth}" MaxHeight="100" /> 
     <RowDefinition Height="600*"/> 
     <RowDefinition Height="{Binding MenuViewModel.BottomMenuHeight}" MaxHeight="70"/> 
    </Grid.RowDefinitions> 

    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="800*"/> 
     <ColumnDefinition Width="{Binding MenuViewModel.RightMenuWidth}" MaxWidth="160"/> 
    </Grid.ColumnDefinitions> 

    <Grid Name="TopMenuGrid" Row="0" Column="0" ColumnSpan="2"> 
     <menu1:MenuContainer x:Name="TopMenu" 
         MenuOrientation="Horizontal" 
         SelectedItem="{Binding MenuViewModel.SelectedHeaderMenuItem, Mode=TwoWay}" 
         MenuItems="{Binding MenuViewModel.HeaderMenuItems}" 
         SelectedTemplate="{StaticResource HeaderMenuSelectedItemTemplate}"> 
     </menu1:MenuContainer> 
    </Grid> 
    <Grid Name="RightMenuGrid" Column="1" Row="1"> 
     <menu1:MenuContainer x:Name="RightMenu" 
         MenuOrientation="Vertical" 
         SelectedItem="{Binding MenuViewModel.SelectedRightItem, Mode=TwoWay}" 
         MenuItems="{Binding MenuViewModel.RightMenuItems}" 
         SelectedTemplate="{StaticResource RightMenuSelectedItemTemplate}"> 
     </menu1:MenuContainer> 

    </Grid> 
    <Grid Row="1" Name="ContentGrid" Column="0" ColumnSpan="1"> 
     <TabControl Name="ContentTabControl" 
       SelectedIndex="{Binding MenuViewModel.SelectedPage}"> 
       <TabItem Header="Home Page"> 
       <TextBlock>Here comes the home page</TextBlock> 
      </TabItem> 
     </TabControl> 
    </Grid> 
    <Grid Name="DetailMenuGrid" Grid.Row="2" ColumnSpan="2" Column="0"> 
     <menu1:MenuContainer Background="Aquamarine" 
         x:Name="BottomMenu" MenuOrientation="Horizontal" 
         SelectedItem="{Binding MenuViewModel.SelectedBottomItemItem, Mode=TwoWay}" 
         MenuItems="{Binding MenuViewModel.BottomMenuItems}" 
         SelectedTemplate="{StaticResource BottomMenuSelectedItemTemplate}"> 
    </menu1:MenuContainer>      
    </Grid> 
</Grid> 

樣式:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
       xmlns:local="clr-namespace:MyApp.Client.Resources" 
       xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
       xmlns:helpers="clr-namespace:MyApp.CommonGui.Helpers;assembly=MyApp.CommonGui"> 
<ControlTemplate x:Key="BottomMenuSelectedItemTemplate" TargetType="ListViewItem"> 
    <Border SnapsToDevicePixels="true" 
       BorderBrush="{TemplateBinding BorderBrush}" 
       BorderThickness="{TemplateBinding BorderThickness}" 
       Background="{TemplateBinding Background}" 
       CornerRadius="5" x:Name="border" 
       > 
     <StackPanel> 
      <Popup PlacementTarget="{Binding ElementName=TextBlockContent}" 
         Child="{Binding SelectedControl}" 
         Width="{TemplateBinding Width}" 
         Placement="Top" VerticalOffset="-2" AllowsTransparency="True" 
         IsOpen="{Binding IsActive, Mode=TwoWay}"> 
       <i:Interaction.Behaviors> 
        <helpers:AutoRepositionPopupBehavior/> 
       </i:Interaction.Behaviors> 
      </Popup> 
      <ContentControl 
       SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
       Margin="0,0,0,0" 
       VerticalAlignment="Center"> 

       <Grid VerticalAlignment="Center"> 
        <ToggleButton 
         Height="64" 
         BorderThickness="0" 
         Background="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background}" 
         VerticalAlignment="Bottom" 
         x:Name="TextBlockContent" 
         Content="{Binding Name}" 
         VerticalContentAlignment="Center" 
         IsChecked="{Binding IsActive}" 
         ></ToggleButton> 
        </Grid> 
      </ContentControl> 
     </StackPanel> 
    </Border> 
</ControlTemplate> 
<ControlTemplate x:Key="HeaderMenuSelectedItemTemplate" TargetType="ListViewItem"> 
    <Border SnapsToDevicePixels="true" 
       BorderBrush="{TemplateBinding BorderBrush}" 
       BorderThickness="{TemplateBinding BorderThickness}" 
       Background="{TemplateBinding Background}" 
       CornerRadius="5" x:Name="border" 
       > 
     <StackPanel> 
      <ContentControl 
       SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
       Margin="0,0,0,0" 
       VerticalAlignment="Center"> 
       <Grid VerticalAlignment="Center"> 
        <Grid> 
         <TextBlock x:Name="TextBlockContent" Text="{Binding 
        </Grid> 
       </Grid> 
      </ContentControl> 
     </StackPanel> 
    </Border> 
</ControlTemplate> 
<ControlTemplate x:Key="RightMenuSelectedItemTemplate" TargetType="ListViewItem"> 
    <Border SnapsToDevicePixels="true" 
       BorderBrush="{TemplateBinding BorderBrush}" 
       BorderThickness="{TemplateBinding BorderThickness}" 
       Background="{TemplateBinding Background}" 
       CornerRadius="5" x:Name="border" 
       > 
     <StackPanel> 
      <ContentControl 
       SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
       Margin="0,0,0,0" 
       VerticalAlignment="Center"> 
       <Grid VerticalAlignment="Center"> 
        <ToggleButton 
         Height="64" 
         BorderThickness="0" 
         Background="{Binding 
           RelativeSource={RelativeSource TemplatedParent}, 
           Path=Background}" 
         VerticalAlignment="Bottom" 
         x:Name="TextBlockContent" 
         Content="{Binding Name}" 
         VerticalContentAlignment="Center" 
         IsChecked="{Binding IsActive}"> 
        </ToggleButton> 
       </Grid> 
      </ContentControl> 
     </StackPanel> 
    </Border> 
</ControlTemplate> 

我希望通過這裏清楚地瞭解我的問題: 我需要知道如何進入MenuContainer用戶控件背後的代碼的SelectedTemplateChanged方法,以便設置ListView的選定項目的樣式。

但我相信這可以做得更優雅。我對「高級」xaml和模板樣式相當陌生,因此我陷入了一些困境。我已經搜索了幾個小時的論壇,試圖找到一個解決方案,但我還沒有成功。

是否有可能在沒有SelectedTemplateChanged後面的代碼的情況下實現這個功能?

任何幫助表示讚賞,直接解決我的問題或替代解決方案。

回答

0

嘗試綁定到UserControlSelectedTemplate財產使用RelativeSource

<Style TargetType="ListViewItem" x:Name="MenuItemStyle"> 
    <Style.Triggers> 
     <Trigger Property="IsSelected" Value="True"> 
      <Setter Property="Background" Value="DarkSeaGreen" /> 
      <Setter Property="Template" Value="{Binding SelectedTemplate, RelativeSource={RelativeSource AncestorType=UserControl}}" /> 
     </Trigger> 
    </Style.Triggers> 
</Style> 
+0

謝謝!這就是我需要的一切:) – yelbow