I have a reusable custom control for search results. It uses ListView GridView to display the search results and it's already used in multiple places in my app.
<views:AbstractDictionaryPickerView x:Class="MyApp.Common.Controls.Dictionaries.Views.AbstractDictionaryPickerView"
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:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:watermark="clr-namespace:MyApp.Common.Controls.Watermark"
xmlns:behaviors="clr-namespace:MyApp.Common.Behaviors"
xmlns:listViewLayout="clr-namespace:Itenso.Windows.Controls.ListViewLayout;assembly=Itenso.Windows.Controls.ListViewLayout"
xmlns:views="clr-namespace:MyApp.Common.Controls.Dictionaries.Views"
xmlns:viewModels="clr-namespace:MyApp.Common.Controls.Dictionaries.ViewModels"
xmlns:design="clr-namespace:MyApp.Common.Controls.Dictionaries.ViewModels.Design"
d:DataContext="{design:DesignMultiDictionaryPickerViewModel}"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Viewbox Stretch="Fill">
<Canvas Width="800" Height="800">
<Rectangle Fill="#ffffffff" Width="800" Height="800" />
<Rectangle Width="5" Height="800" >
<Rectangle.Fill>
<LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
<GradientStop Color="#FFCAEBF4"/>
<GradientStop Color="#FFCEF5FF" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
</Canvas>
</Viewbox>
<Grid Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<TextBox
Grid.Row="0" Height="Auto"
Margin="5,0,5,0"
Style="{StaticResource TextBoxStyle}"
Text="{Binding SearchQuery, UpdateSourceTrigger=PropertyChanged}">
<i:Interaction.Behaviors>
<watermark:TextBoxWatermarkBehavior Label="{Binding WatermarkText, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}"
LabelStyle="{StaticResource WatermarkStyle}"/>
<behaviors:SelectAllWhenTextBoxFocusedBehavior/>
<behaviors:TextBoxArrowUpDownNavigationBehavior/>
<behaviors:SetLogicalFocusBehavior/>
</i:Interaction.Behaviors>
</TextBox>
<Grid Grid.Row="1">
<ListView listViewLayout:ListViewLayoutManager.Enabled="True" x:Name="SearchResultsList"
ItemsSource="{Binding FilteredElements}"
ScrollViewer.VerticalScrollBarVisibility="Auto" Margin="5,2,5,3"
SelectionMode="Single"
>
<ListView.Resources>
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource TextBlockStyle}"/>
</ListView.Resources>
<i:Interaction.Behaviors>
<behaviors:ArrowNavigationBehavior/>
<behaviors:AutoSizeListViewColumns/>
</i:Interaction.Behaviors>
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseDoubleClick">
<i:InvokeCommandAction Command="{Binding ChooseItemCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}, Path=SelectedItem}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<ListView.InputBindings>
<KeyBinding Key="Enter"
Command="{Binding ChooseItemCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}, Path=SelectedItem}" />
<MouseBinding MouseAction="LeftDoubleClick"
Command="{Binding ChooseItemCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}, Path=SelectedItem}" />
</ListView.InputBindings>
<ListView.View>
<!-- GRIDVIEW TO REPLACE -->
<GridView ColumnHeaderContainerStyle="{StaticResource {x:Type GridViewColumnHeader}}" x:Name="ElementsGridView">
<GridViewColumn Header="">
<GridViewColumn.CellTemplate>
<DataTemplate DataType="viewModels:ChoosableViewModel">
<CheckBox IsChecked="{Binding IsChosen}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
</Grid>
</Grid>
</views:AbstractDictionaryPickerView>
The consuming code looks like that:
<UserControl x:Class="MyApp.Modules.Management.OnlineRegistrationSettings.Tabs.AvailableDoctors.OnlineRegistrationDoctorsSettingsView"
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:views="clr-namespace:MyApp.Common.Controls.Dictionaries.Views;assembly=MyApp.Common"
xmlns:onlineRegistrationSettings="clr-namespace:MyApp.Modules.Management.OnlineRegistrationSettings"
d:DataContext="{d:DesignInstance onlineRegistrationSettings:OnlineRegistrationSettingsViewModel}"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Style="{StaticResource LabelStyle}" Content="Wybór lekarzy, którzy mają być dostępni w rejestracji online."/>
<!-- HERE -->
<views:AbstractDictionaryPickerView DataContext="{Binding MultiDictionaryPickerViewModel}" Grid.Row="1"
Configuration="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}, Path=DataContext.Configuration}"/>
</Grid>
</UserControl>
Now I want do modify the GridView columns (add a new column with ComboBox).
Is it possible to override the GridView element of the views:AbstractDictionaryPickerView in the XAML of the consuming code? I mean what's below <!-- GRIDVIEW TO REPLACE --> tag in the first snippet.
Is it possible to override the GridView element of the views:AbstractDictionaryPickerView in the XAML of the consuming code?
No. At least not using only XAML.
But if you add a property to your AbstractDictionaryPickerView control that exposes the view of the ListView:
public partial class AbstractDictionaryPickerView : UserControl
{
public AbstractDictionaryPickerView()
{
InitializeComponent();
}
public ViewBase GridView
{
get { return SearchResultsList.View; }
set { SearchResultsList.View = value; }
}
}
...you could set the it to a new GridView in the consuming XAML markup:
<views:AbstractDictionaryPickerView>
<views:AbstractDictionaryPickerView.GridView>
<GridView>
<GridView.Columns>
<GridViewColumn Header="..." DisplayMemberBinding="{Binding}" />
</GridView.Columns>
</GridView>
</views:AbstractDictionaryPickerView.GridView>
</views:AbstractDictionaryPickerView>
Related
I have used grid extra to design individual responsive components in my WPF application. I have a View like following:
<UserControl x:Class="..."
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:local="clr-namespace:..."
mc:Ignorable="d"
xmlns:ge="clr-namespace:SourceChord.GridExtra;assembly=GridExtra.Wpf">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="...">
</ResourceDictionary>
<ResourceDictionary Source="...">
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<UserControl.Width>
<StaticResource ResourceKey="ApplicationWidth" />
</UserControl.Width>
<Grid Style="{StaticResource SelectContainer}"
ge:GridEx.RowDefinition="1*, 3*"
ge:GridEx.TemplateArea="Message/ Companies/">
<Grid ge:GridEx.AreaName="Message"
ge:GridEx.RowDefinition="*"
ge:GridEx.ColumnDefinition="*,*"
ge:GridEx.TemplateArea="L1 L2/"
>
<TextBlock Text="{Binding Path=MessageL1Text}" Style="{StaticResource MessageTextStyle}" ge:GridEx.AreaName="L1"/>
<TextBlock Text="{Binding Path=MessageL2Text}" Style="{StaticResource MessageTextUrduStyle}" ge:GridEx.AreaName="L2"/>
</Grid>
<Grid ge:GridEx.AreaName="Companies"
ge:GridEx.RowDefinition="*"
ge:GridEx.ColumnDefinition="1*,1.5*,1.5*,1.5*,1.5*,1.5*,1.5*,1*"
ge:GridEx.TemplateArea="MarginLeft Company1 Company2 Company3 Company4 Company5 More MarginRight/">
<Grid ge:GridEx.AreaName="MarginLeft"></Grid>
<Grid ge:GridEx.AreaName="MarginRight"></Grid>
<Grid ge:GridEx.AreaName="Company1" Style="{StaticResource CompanyButtonOneStyle}">
<Grid.Resources>
<ImageBrush x:Key="AddButtonImageBrush" ImageSource="{Binding Path=CompanyOne.ButtonImagePath}" Stretch="Uniform"/>
</Grid.Resources>
<Button Command="{Binding Path=CompanyOneClick}" Height="Auto" Width="Auto" Background="{StaticResource AddButtonImageBrush}" Style="{StaticResource CompanyButton}" Visibility="{Binding Path=CompanyOne.IsVisible}" IsEnabled="{Binding Path=CompanyOne.IsActive}">
</Button>
</Grid>
<Grid ge:GridEx.AreaName="Company2" Style="{StaticResource CompanyButtonTwoStyle}">
<Grid.Resources>
<ImageBrush x:Key="AddButtonImageBrush" ImageSource="{Binding Path=CompanyTwo.ButtonImagePath}" Stretch="Uniform"/>
</Grid.Resources>
<Button Command="{Binding Path=CompanyTwoClick}" Height="Auto" Width="Auto" Background="{StaticResource AddButtonImageBrush}" Style="{StaticResource CompanyButton}" Visibility="{Binding Path=CompanyTwo.IsVisible}" IsEnabled="{Binding Path=CompanyTwo.IsActive}">
</Button>
</Grid>
<Grid ge:GridEx.AreaName="Company3" Style="{StaticResource CompanyButtonThreeStyle}">
<Grid.Resources>
<ImageBrush x:Key="AddButtonImageBrush" ImageSource="{Binding Path=CompanyThree.ButtonImagePath}" Stretch="Uniform"/>
</Grid.Resources>
<Button Command="{Binding Path=CompanyThreeClick}" Height="Auto" Width="Auto" Background="{StaticResource AddButtonImageBrush}" Style="{StaticResource CompanyButton}" Visibility="{Binding Path=CompanyThree.IsVisible}" IsEnabled="{Binding Path=CompanyThree.IsActive}">
</Button>
</Grid>
<Grid ge:GridEx.AreaName="Company4" Style="{StaticResource CompanyButtonFourStyle}">
<Grid.Resources>
<ImageBrush x:Key="AddButtonImageBrush" ImageSource="{Binding Path=CompanyFour.ButtonImagePath}" Stretch="Uniform"/>
</Grid.Resources>
<Button Command="{Binding Path=CompanyFourClick}" Height="Auto" Width="Auto" Background="{StaticResource AddButtonImageBrush}" Style="{StaticResource CompanyButton}" Visibility="{Binding Path=CompanyFour.IsVisible}" IsEnabled="{Binding Path=CompanyFour.IsActive}">
</Button>
</Grid>
<Grid ge:GridEx.AreaName="Company5" Style="{StaticResource CompanyButtonFiveStyle}">
<Grid.Resources>
<ImageBrush x:Key="AddButtonImageBrush" ImageSource="{Binding Path=CompanyFive.ButtonImagePath}" Stretch="Uniform"/>
</Grid.Resources>
<Button Command="{Binding Path=CompanyFiveClick}" Height="Auto" Width="Auto" Background="{StaticResource AddButtonImageBrush}" Style="{StaticResource CompanyButton}" Visibility="{Binding Path=CompanyFive.IsVisible}" IsEnabled="{Binding Path=CompanyFive.IsActive}">
</Button>
</Grid>
<Grid ge:GridEx.AreaName="More" Style="{StaticResource MoreButtonStyle}">
<Grid.Resources>
<ImageBrush x:Key="AddButtonImageBrush" ImageSource="{Binding Path=More.ButtonImagePath}" Stretch="Uniform"/>
</Grid.Resources>
<Button Command="{Binding Path=MoreClick}" Height="Auto" Width="Auto" Background="{StaticResource AddButtonImageBrush}" Style="{StaticResource CompanyButton}" Visibility="{Binding Path=More.IsVisible}" IsEnabled="{Binding Path=More.IsActive}">
</Button>
</Grid>
</Grid>
</Grid>
Next what I require was to bring a disable panel to flood over this user control disabling all the controls and graying out the UI like:
<UserControl x:Class="..."
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:local="clr-namespace:..."
mc:Ignorable="d"
xmlns:ge="clr-namespace:SourceChord.GridExtra;assembly=GridExtra.Wpf">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="...">
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid Style="{StaticResource DisableGridStyle}" Opacity="0.8" Background="Gray">
</Grid>
As you can see next I wrap both in a container Panel and will keep the disabled control hidden till I want it to appear on top of the actual panel using Grid and Grid.Zindex in somewhat manner like explained in this answer.
I have tried it and it works like a charm.
So now let's move on to my actual requirement which is to bring up one of the child component of the actual panel say the following on top while keeping the others behind the disabled panel;
<Grid ge:GridEx.AreaName="Company1" Style="{StaticResource CompanyButtonOneStyle}">
<Grid.Resources>
<ImageBrush x:Key="AddButtonImageBrush" ImageSource="{Binding Path=CompanyOne.ButtonImagePath}" Stretch="Uniform"/>
</Grid.Resources>
<Button Command="{Binding Path=CompanyOneClick}" Height="Auto" Width="Auto" Background="{StaticResource AddButtonImageBrush}" Style="{StaticResource CompanyButton}" Visibility="{Binding Path=CompanyOne.IsVisible}" IsEnabled="{Binding Path=CompanyOne.IsActive}">
</Button>
</Grid>
I tried to do it by tweaking the Z-index for the said component but it did not work for me. I do not know if this is being caused by grid extra but using grid extra is a constraint that I cannot let go. Thus, what I need is a solution to get the required results using grid extra. Thanks in advance.
Note details about GridExtra can be viewed here.
Z Index is used to control the ordering of the elements that are at the same level in your components heirarchy. As per you state that:
As you can see next I wrap both in a container Panel and will keep the disabled control hidden till I want it to appear on top of the actual panel using Grid and Grid.Zindex
I believe in doing so, your required component is not at the same level as your disable panel and it would not be possible to bring it up using the Z-Index.
One alternate solution that I can think of is to have multiple disable panels with same properties and use one at the same sibling level at the component that you wish to send back or bring in front.
As an example consider the following code:
<Window x:Class="ZindexForVaryingChildren.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ZindexForVaryingChildren"
xmlns:ge="clr-namespace:SourceChord.GridExtra;assembly=GridExtra.Wpf"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid ge:GridEx.RowDefinition="*,*"
ge:GridEx.TemplateArea="R1/ R2/" Opacity="0.8" Background="Red">
<TextBlock Opacity="0.8" Background="Red" Grid.ZIndex="2" ge:GridEx.Area="0,0,2,2" HorizontalAlignment="Stretch"/>
<Grid ge:GridEx.AreaName="R1" Grid.ZIndex="1">
<TextBlock TextWrapping="Wrap" Text="Hello" FontSize="40"/>
</Grid>
<Grid ge:GridEx.AreaName="R2" Grid.ZIndex="3">
<TextBlock TextWrapping="Wrap" Text="Hello" FontSize="40"/>
</Grid>
</Grid>
Here you can see even using the GridExtra I have tried to illustrate how you can bring the R2 to front when pushing R1 to back. Also using the TextBlock as the disabler panel while you can use the component you wish.
The above will yield output as follows:
Also note this is one of the suggested solution you can totally work out a strategy of your own but have to keep in mind that Z-Index only works for siblings.
I ended up using my disable component as a sibling to the hierarchy as:
<UserControl x:Class="..."
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:local="clr-namespace:..."
mc:Ignorable="d"
xmlns:ge="clr-namespace:SourceChord.GridExtra;assembly=GridExtra.Wpf">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="...">
</ResourceDictionary>
<ResourceDictionary Source="...">
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<UserControl.Width>
<StaticResource ResourceKey="ApplicationWidth" />
</UserControl.Width>
<Grid Style="{StaticResource NetworkSelectContainer}"
ge:GridEx.RowDefinition="1*, 3*"
ge:GridEx.TemplateArea="Message/ Companies/">
<Grid ge:GridEx.AreaName="Message"
ge:GridEx.RowDefinition="*"
ge:GridEx.ColumnDefinition="*,*"
ge:GridEx.TemplateArea="L1 L2/"
>
<local:DisablePanel Panel.ZIndex="3" ge:GridEx.Area="0,0,2,2" x:Name="DisableMessage"></local:DisablePanel>
<TextBlock Text="{Binding Path=MessageText}" Style="{StaticResource MessageTextStyle}" ge:GridEx.AreaName="L1"/>
<TextBlock Text="{Binding Path=MessageUrduText}" Style="{StaticResource MessageTextStyle}" ge:GridEx.AreaName="L2"/>
</Grid>
<Grid ge:GridEx.AreaName="Companies"
ge:GridEx.RowDefinition="*"
ge:GridEx.ColumnDefinition="1*,1.5*,1.5*,1.5*,1.5*,1.5*,1.5*,1*"
ge:GridEx.TemplateArea="MarginLeft Company1 Company2 Company3 Company4 Company5 More MarginRight/">
<local:DisablePanel ge:GridEx.Area="0,0,1,8" Panel.ZIndex="3" x:Name="DisableCompany"></local:DisablePanel>
<Grid ge:GridEx.AreaName="MarginLeft"></Grid>
<Grid ge:GridEx.AreaName="MarginRight"></Grid>
<Grid ge:GridEx.AreaName="Company1" Style="{StaticResource CompanyButtonOneStyle}">
<Grid.Resources>
<ImageBrush x:Key="AddButtonImageBrush" ImageSource="{Binding Path=CompanyOne.ButtonImagePath}" Stretch="Uniform"/>
</Grid.Resources>
<Button Command="{Binding Path=CompanyOneClick}" Height="Auto" Width="Auto" Background="{StaticResource AddButtonImageBrush}" Style="{StaticResource CompanyButton}" Visibility="{Binding Path=CompanyOne.IsVisible}" IsEnabled="{Binding Path=CompanyOne.IsActive}">
</Button>
</Grid>
<Grid ge:GridEx.AreaName="Company2" Style="{StaticResource CompanyButtonTwoStyle}">
<Grid.Resources>
<ImageBrush x:Key="AddButtonImageBrush" ImageSource="{Binding Path=CompanyTwo.ButtonImagePath}" Stretch="Uniform"/>
</Grid.Resources>
<Button Command="{Binding Path=CompanyTwoClick}" Height="Auto" Width="Auto" Background="{StaticResource AddButtonImageBrush}" Style="{StaticResource CompanyButton}" Visibility="{Binding Path=CompanyTwo.IsVisible}" IsEnabled="{Binding Path=CompanyTwo.IsActive}">
</Button>
</Grid>
<Grid ge:GridEx.AreaName="Company3" Style="{StaticResource CompanyButtonThreeStyle}">
<Grid.Resources>
<ImageBrush x:Key="AddButtonImageBrush" ImageSource="{Binding Path=CompanyThree.ButtonImagePath}" Stretch="Uniform"/>
</Grid.Resources>
<Button Command="{Binding Path=CompanyThreeClick}" Height="Auto" Width="Auto" Background="{StaticResource AddButtonImageBrush}" Style="{StaticResource CompanyButton}" Visibility="{Binding Path=CompanyThree.IsVisible}" IsEnabled="{Binding Path=CompanyThree.IsActive}">
</Button>
</Grid>
<Grid ge:GridEx.AreaName="Company4" Style="{StaticResource CompanyButtonFourStyle}">
<Grid.Resources>
<ImageBrush x:Key="AddButtonImageBrush" ImageSource="{Binding Path=CompanyFour.ButtonImagePath}" Stretch="Uniform"/>
</Grid.Resources>
<Button Command="{Binding Path=CompanyFourClick}" Height="Auto" Width="Auto" Background="{StaticResource AddButtonImageBrush}" Style="{StaticResource CompanyButton}" Visibility="{Binding Path=CompanyFour.IsVisible}" IsEnabled="{Binding Path=CompanyFour.IsActive}">
</Button>
</Grid>
<Grid ge:GridEx.AreaName="Company5" Style="{StaticResource CompanyButtonFiveStyle}">
<Grid.Resources>
<ImageBrush x:Key="AddButtonImageBrush" ImageSource="{Binding Path=CompanyFive.ButtonImagePath}" Stretch="Uniform"/>
</Grid.Resources>
<Button Command="{Binding Path=CompanyFiveClick}" Height="Auto" Width="Auto" Background="{StaticResource AddButtonImageBrush}" Style="{StaticResource CompanyButton}" Visibility="{Binding Path=CompanyFive.IsVisible}" IsEnabled="{Binding Path=CompanyFive.IsActive}">
</Button>
</Grid>
<Grid ge:GridEx.AreaName="More" Style="{StaticResource MoreButtonStyle}">
<Grid.Resources>
<ImageBrush x:Key="AddButtonImageBrush" ImageSource="{Binding Path=More.ButtonImagePath}" Stretch="Uniform"/>
</Grid.Resources>
<Button Command="{Binding Path=MoreClick}" Height="Auto" Width="Auto" Background="{StaticResource AddButtonImageBrush}" Style="{StaticResource CompanyButton}" Visibility="{Binding Path=More.IsVisible}" IsEnabled="{Binding Path=More.IsActive}">
</Button>
</Grid>
</Grid>
</Grid>
Although using much of the approach in the above answer yet adding it for clarifying idea to others.
I'm using MVVM pattern in WPF. My small project contains 1x Window and 3x UserControls. Each UserControl represents tab, please see the picture below.
Solution structure
What I'm trying to do is to bind the Window Title to the variable in each tab model. I tried to use Interaction.Triggers and event name "Loaded". The command "ChangeTitle" works fine when I switch between different views but when I select tab with the same view as previously selected tab then title doesn't change until I switch to another tab with different view. I tried other events but couldn't find any for this purpose. I would like to trigger the above command after tab selection changed. Please advise. Thank you.
MainWindow.xaml
<Window x:Class="LSS_doc.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:intr="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:models="clr-namespace:LSS_doc.Models"
xmlns:Views="clr-namespace:LSS_doc.Views"
mc:Ignorable="d"
Height="350" Width="525"
MinHeight="350"
MinWidth="525">
<Grid>
<intr:Interaction.Triggers>
<intr:EventTrigger EventName="Loaded">
<intr:InvokeCommandAction Command="{Binding CreateMainTab}"/>
</intr:EventTrigger>
</intr:Interaction.Triggers>
<DockPanel>
<TabControl Name="tabControl" ItemsSource="{Binding Tabs}" SelectedIndex="{Binding TabIndex}">
<TabControl.Resources>
<DataTemplate DataType="{x:Type models:MainTabModel}">
<Views:MainTabView/>
</DataTemplate>
<DataTemplate DataType="{x:Type models:ResultTabModel}">
<Views:ResultTabView/>
</DataTemplate>
<DataTemplate DataType="{x:Type models:DisplayTabView}">
<Views:DisplayTabView/>
</DataTemplate>
</TabControl.Resources>
<TabControl.ItemTemplate>
<DataTemplate DataType="{x:Type models:ITabModel}">
<TextBlock>
<Run Text="{Binding Name}"/>
<Hyperlink Command="{Binding CloseCommand}" ><Run Text="{Binding CloseButton}"/></Hyperlink>
</TextBlock>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
</DockPanel>
</Grid>
MainTabView.xaml
<UserControl x:Class="LSS_doc.Views.MainTabView"
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:intr="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<intr:Interaction.Triggers>
<intr:EventTrigger EventName="Loaded">
<intr:InvokeCommandAction CommandParameter="{Binding Name}" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.ChangeTitle}"/>
</intr:EventTrigger>
</intr:Interaction.Triggers>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBox Name="searchBox" Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.Keywords}" Margin="10,10,10,10" Height="30"/>
<Button Name="searchButton" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.Search}" Grid.Column="1" Margin="0,0,10,0" Height="30"/>
<TreeView Grid.Row="1" Grid.ColumnSpan="2" Margin="10,0,10,10" BorderThickness="0">
<TreeViewItem Header="{Binding Name}" IsExpanded="True">
<TreeViewItem Header="Level 2.1" />
<TreeViewItem Header="Level 2.2" IsExpanded="True">
<TreeViewItem Header="Level 3.1" />
<TreeViewItem Header="Level 3.2" />
</TreeViewItem>
<TreeViewItem Header="Level 2.3" />
</TreeViewItem>
</TreeView>
</Grid>
ResultTabView.xaml
<UserControl x:Class="LSS_doc.Views.ResultTabView"
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:intr="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<intr:Interaction.Triggers>
<intr:EventTrigger EventName="Loaded">
<intr:InvokeCommandAction CommandParameter="{Binding Name}" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.ChangeTitle}"/>
</intr:EventTrigger>
</intr:Interaction.Triggers>
<Grid>
<ListBox x:Name="FileList" ItemsSource="{Binding Result}">
<ListBox.ItemTemplate>
<DataTemplate DataType="string">
<TextBlock>
<Hyperlink CommandParameter="{Binding}" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.DisplayFile}">
<TextBlock Text="{Binding}"/>
</Hyperlink>
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
DisplayTabView.xaml
<UserControl x:Class="LSS_doc.Views.DisplayTabView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:intr="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:LSS_doc.Helpers"
xmlns:ns="clr-namespace:LSS_doc.Helpers"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<intr:Interaction.Triggers>
<intr:EventTrigger EventName="Loaded">
<intr:InvokeCommandAction CommandParameter="{Binding Name}" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.ChangeTitle}"/>
</intr:EventTrigger>
</intr:Interaction.Triggers>
<Grid >
<WebBrowser local:WebBrowserExtensions.BindableSource="{Binding FileUrl}" local:WebBrowserExtensions.BindableLoaded="{Binding AcceptedKeywords}"/>
</Grid>
You can bind Window Title directly to model using ElementName:
<Window Title="{Binding ElementName=tab,Path=SelectedItem.WindowTitleForThisTab}">
My requirement is to group datagrid rows based on a condition and display the grouped rows in alternating colours along with an edit button for each group. The problem here is my datagrid Column headers are not aligning with the Data grid data rows .
Current Grid
I have already gone through a lot of posts with not much help I have tried this post as well WPF DataGrid GroupStyle . This example has group style for a grid but I tried to do the same for a datagrid.
Current XAML
<Window x:Class="TimeSeriesDataGrid.View.TimeSeriesView"
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"
mc:Ignorable="d" Width="Auto" Height="Auto"
xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
xmlns:viewmodel="clr-namespace:TimeSeriesDataGrid.ViewModel"
xmlns:converter="clr-namespace:TimeSeriesDataGrid.Converters"
xmlns:local="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WPF45"
xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WPF45"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" Title="{Binding WindowTitle}" ResizeMode="CanMinimize">
<Window.DataContext>
<viewmodel:TimeSeriesViewModel />
</Window.DataContext>
<Window.Background>
<LinearGradientBrush EndPoint="0.5,1" MappingMode="RelativeToBoundingBox" StartPoint="0.5,0">
<GradientStop Color="Black" Offset="1"/>
<GradientStop Color="#FFEEEFFF" Offset="0.836"/>
</LinearGradientBrush>
</Window.Background>
<Window.Resources>
<converter:RowColorConverter x:Key="RowColorConverter" />
<CollectionViewSource x:Key="TimeSeriesCollectionViewSource" CollectionViewType="ListCollectionView" Source="{Binding GetTimeSeries}" >
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="DocumentId"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</Window.Resources>
<Grid Margin="0,0,0,-3">
<Grid.RowDefinitions>
<RowDefinition Height="8*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<DataGrid
DataContext="{StaticResource TimeSeriesCollectionViewSource}"
SelectedItem="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.SelectedTimeSeries}"
ItemsSource="{Binding}"
CanUserReorderColumns="False"
SnapsToDevicePixels="True"
Grid.Column="0"
Grid.Row="0"
x:Name="dg_TimeSeriesEdit"
AutoGenerateColumns="False"
CanUserResizeColumns="False"
ScrollViewer.IsDeferredScrollingEnabled="True"
VirtualizingStackPanel.IsVirtualizing="true"
HeadersVisibility="Column"
HorizontalContentAlignment="Center"
CanUserAddRows="False"
CanUserDeleteRows="False"
MaxHeight="800"
MaxWidth="2550"
HorizontalGridLinesBrush="#FFC92222"
VerticalGridLinesBrush="#FFC92222"
Width="Auto"
Height="Auto" >
<DataGrid.GroupStyle>
<GroupStyle AlternationCount="2" >
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<StackPanel Orientation="Vertical" VerticalAlignment="Center" Background="Transparent">
<Button Grid.Column="0" BorderThickness="0" Content="Edit" Margin="0,0,0,5" Height="Auto" Width="50" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<local:EventToCommand Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.EditGroupCmd}" CommandParameter="{Binding Path=Items}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</StackPanel>
<ItemsPresenter />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
<DataGrid.RowStyle>
<Style>
<Setter Property="DataGridRow.Background"
Value="{Binding RelativeSource={RelativeSource AncestorType=GroupItem},
Path=(ItemsControl.AlternationIndex), Converter={StaticResource RowColorConverter}}"/>
</Style>
</DataGrid.RowStyle>
<DataGrid.Columns >
.
.
</DataGrid.Columns>
</DataGrid>
</Grid>
</Grid>
</Window>
Any Help would be appreciated.
I managed to allign the header with data after TranslateTransform on datagridcolumn header
<DataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="RenderTransform">
<Setter.Value>
<TranslateTransform X="50"></TranslateTransform>
</Setter.Value>
</Setter>
</Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.RowValidationErrorTemplate>
My ListBox uses this DataTemplate to act on LeftDoubleClick:
<UserControl x:Class="X1.XPrep.GuiModuleJobSelection.Views.ContentJobSelectionView"
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:l="http://wpflocalizeextension.codeplex.com"
xmlns:Classes="clr-namespace:X1.XPrep.GuiModuleJobSelection.Models"
xmlns:ViewModels="clr-namespace:X1.XPrep.GuiModuleJobSelection.ViewModels"
l:LocalizeDictionary.DesignCulture="en"
l:ResxLocalizationProvider.DefaultAssembly="XPrep.GuiModuleJobSelection"
l:ResxLocalizationProvider.DefaultDictionary="Resources"
x:Name="jobSelectionContent"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance {x:Type ViewModels:ContentJobSelectionViewModel}, IsDesignTimeCreatable=True}"
d:DesignHeight="600" d:DesignWidth="328.5">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/XPrep.GuiCommon;component/Resources/Styles.xaml"/>
</ResourceDictionary.MergedDictionaries>
<DataTemplate x:Key="ListboxJobDataTemplate" DataType="{x:Type Classes:JobForJobSelectionViewModel}">
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding JobData.JobName}"
VerticalAlignment="Top">
<TextBlock.ToolTip>
<StackPanel Height="200" MinWidth="200">
<StackPanel Width="200" Orientation="Vertical" >
<TextBlock Text="{Binding JobData.JobName}" FontWeight="Bold"/>
<Image VerticalAlignment="Top" Source="{Binding PreviewImageSource}" Margin="0,10,0,0"/>
<TextBlock Text="No preview image available." Margin="0,10,0,0">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsPreviewImageMissing}" Value="False">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<TextBlock Text="{Binding JobData.Comment}"/>
</StackPanel>
</StackPanel>
</TextBlock.ToolTip>
<TextBlock.InputBindings>
<MouseBinding Gesture="LeftDoubleClick"
Command="{Binding Path=DataContext.LoadCommand,
RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type UserControl}}}"/>
</TextBlock.InputBindings>
</TextBlock>
</DataTemplate>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<ListBox ItemsSource="{Binding Jobs, Mode=TwoWay}" IsSynchronizedWithCurrentItem="True"
SelectedItem="{Binding SelectedJob, Mode=TwoWay}" ItemTemplate="{DynamicResource ListboxJobDataTemplate}"
Grid.Column="1" Grid.Row="0" x:Name="listBoxJobNames" MinWidth="200"
HorizontalAlignment="Stretch" Margin="6" VerticalAlignment="Stretch">
<ListBox.InputBindings>
<KeyBinding Key="Delete" Command="{Binding Path=DataContext.DeleteCommand,
RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type UserControl}}}"/>
</ListBox.InputBindings>
</ListBox>
<StackPanel Grid.Column="0" Grid.Row="0" Margin="0" Width="100" Background="{DynamicResource ContextBackgroundBrush}">
<Button x:Name="jobSelectionNewButton" Content="{DynamicResource X1.Job.New}" ToolTip="{l:Loc JobSelection_Button_New}"
HorizontalAlignment="Left" Margin="6" VerticalAlignment="Top" Command="{Binding NewCommand}" IsDefault="True"
Style="{StaticResource GlossyButtonX1}"/>
<Button Content="{DynamicResource X1.Job.Load}" ToolTip="{l:Loc JobSelection_Button_Load}"
HorizontalAlignment="Left" Margin="6" VerticalAlignment="Top"
Style="{StaticResource GlossyButtonX1}"
Command="{Binding LoadCommand}"/>
<Button Content="{DynamicResource X1.Job.Rename}" ToolTip="{l:Loc JobSelection_Button_Rename}"
HorizontalAlignment="Left" Margin="6" VerticalAlignment="Top"
Style="{StaticResource GlossyButtonX1}"
Command="{Binding RenameCommand}"/>
<Button Content="{DynamicResource X1.Job.Clone}" ToolTip="{l:Loc JobSelection_Button_Clone}"
HorizontalAlignment="Left" Margin="6" VerticalAlignment="Top"
Style="{StaticResource GlossyButtonX1}"
Command="{Binding CloneCommand}"/>
<Button Content="{DynamicResource X1.Common.Delete}" ToolTip="{l:Loc JobSelection_Button_Delete}"
HorizontalAlignment="Left" Margin="6" VerticalAlignment="Top"
Style="{StaticResource GlossyButtonX1}"
Command="{Binding DeleteCommand}"/>
</StackPanel>
</Grid>
The double click only works on the actual text in the items line.
What can I do, to let the double click also work on the empty spaces to the right of my item text?
Regards
Rainer
Set ListBoxItems' HorizontalContentAlignment = Stretch.
For example:
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
In case, above code doesn't work, also try setting the Background of the Grid to Transparent (if you are using Grid):
<Grid Background="Transparent">
EDIT:
Bind TextBlock Width to ListBoxItem Width as shown below should fix the issue:
<TextBlock HorizontalAlignment="Left"
TextWrapping="Wrap"
Text="{Binding JobData.JobName}"
VerticalAlignment="Top"
Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}, Path=ActualWidth}">
I am trying to bind to an element from a context menu inside a drop-down menu button (from http://shemesh.wordpress.com/2011/10/27/wpf-menubutton/). Even though outside the context menu the binding seems to work, the binding inside the context menu does not.
This is the XAML (very simplified):
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto" CanContentScroll="False">
<ListBox x:Name="lbScenarios" HorizontalContentAlignment="Stretch">
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<ItemsPresenter Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}, Path=ActualWidth}"/>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border>
<Expander>
<Expander.Header>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Margin="5,0,0,0" Grid.Column="0" VerticalAlignment="Center">Results</TextBlock>
<local:MenuButton Grid.Column="3" Content="Menu" Margin="5,0,0,0" VerticalAlignment="Center">
<local:MenuButton.Menu>
<ContextMenu>
<MenuItem Header="Save pie chart as image"
Command="{Binding SaveChartImageCommand}"
CommandParameter="{Binding ElementName=pieChart}" />
<MenuItem Header="Save bar chart as image"
Command="{Binding SaveChartImageCommand}"
CommandParameter="{Binding ElementName=barChart}" />
</ContextMenu>
</local:MenuButton.Menu>
</local:MenuButton>
</Grid>
</Expander.Header>
<Expander.Content>
<StackPanel>
<Image x:Name="pieChart" />
<Image x:Name="barChart" />
</StackPanel>
</Expander.Content>
</Expander>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListBox>
</ScrollViewer>
</Grid>
</Window>
The binding that does not work is the {Binding ElementName=pieChart}, which is funny because the command is being found. I couldn't seem to get a RelativeSource to work, but can someone help me with getting the binding correct?
Since ContextMenu doesn't lie in same Visual tree as that of its placement target so ElementName binding won't work because it requires both controls to be in same Visual tree.
Try using x:Reference which doesn't have this constraint of to be in same visual tree.
CommandParameter="{Binding Source={x:Reference pieChart}}"
OR
use it like this
CommandParameter="{x:Reference pieChart}"
Note - x:Reference will be found in WPF 4.0 or later.