I am trying to bind the background color of a TextBox and use a converter. However, I can't figure out the correct binding due to the TextBox being in a DataTemplate and in a ContentControl.
The DebuggingConverter doesn't fire unless I set the binding path from Path=StateColor to Path=.
Here is the xaml :
<GridViewColumn Header="Value" Width="{Binding SelectedDeviceCol2, Source={x:Static properties:Settings.Default}, Mode=TwoWay}" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<ContentControl Content="{Binding Path=Value, Mode=TwoWay}" IsEnabled="{Binding Path=ReadOnly, Converter={StaticResource readOnlyToEnabledConverter}}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type viewModels:VMDeviceCommand}">
<Button Content="{Binding Name}" Height="24" IsEnabled="True" Click="Button_Click_GetObjectProperty"/>
</DataTemplate>
<DataTemplate DataType="{x:Type System:DateTime}">
<DatePicker SelectedDate="{Binding Path=.}"
SelectedDateFormat="Short"
FirstDayOfWeek="Monday"
IsTodayHighlighted="True" >
</DatePicker>
</DataTemplate>
<DataTemplate DataType="{x:Type System:String}">
<TextBox Text="{Binding Path=.}" TextChanged="TextBox_OnTextChanged">
<TextBox.Background>
<SolidColorBrush Color="{Binding RelativeSource={RelativeSource AncestorType=ContentControl}, Path=StateColor, Converter={StaticResource DebuggingConverter}}"/>
</TextBox.Background>
</TextBox>
</DataTemplate>
<DataTemplate DataType="{x:Type System:UInt16}">
<xctk:IntegerUpDown Text="{Binding Path=.}" ValueChanged="UpDownBase_OnValueChanged" >
</xctk:IntegerUpDown>
</DataTemplate>
<DataTemplate DataType="{x:Type System:Boolean}">
<CheckBox IsChecked="{Binding Path=.}" Click="CheckBox_Click"/>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
</DataTemplate>
</GridViewColumn.CellTemplate>
ContentControl doesn't have a StateColor property, so the Binding never gets its value and never has anything to pass to a converter.
If the ContentControl's DataContext has a StateColor property, that's easy:
<SolidColorBrush
Color="{Binding DataContext.StateColor, RelativeSource={RelativeSource AncestorType=ContentControl}, Converter={StaticResource DebuggingConverter}}"
/>
Related
I am new to WPF and try to do the following:
I have a ListView with a ItemsSource using a ViewModel.
Inside, there is a GridView with Columns. Each Column represents a Preoperty of the View Model. But the Description is optional and can be rather long. So I want to use a Expander. My Problem is, that I can only manage the expander to be as big as the Name-Column. But I want the expander to be as big as the whole row.
Here are 2 Images to clarify what I want.
My current State:
https://i.stack.imgur.com/ZNA4v.png
What I want to achieve:
https://i.stack.imgur.com/ZmFq1.png
I tried "grouping the GridView" but without success... See here
http://technico.qnownow.com/grouping-gridview-wpf/
Here's my Code
<Window ...>
<Window.Resources>
...
</Window.Resources>
<DockPanel>
<StackPanel DockPanel.Dock="Top">
...
</StackPanel>
<Grid>
<ListView Grid.RowSpan="4" DockPanel.Dock="Top" Margin="10" ItemsSource="{Binding MyView}">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="BorderBrush" Value="Black"></Setter>
<Setter Property="BorderThickness" Value="0,0,0,1"></Setter>
<Setter Property="Focusable" Value="False" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Top"></Setter>
<Setter Property="VerticalContentAlignment" Value="Top"></Setter>
</Style>
</ListView.ItemContainerStyle>
<!-- New GridView -->
<ListView.View>
<GridView>
<!--Number-->
<GridViewColumn Header="#">
<GridViewColumn.CellTemplate>
<DataTemplate DataType="viewModel:MyViewModel">
<TextBlock Text="{Binding Model.Number, StringFormat='#{0}', Mode=OneWay}"
Width="20" TextAlignment="Left" Margin="5" VerticalAlignment="Top" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<!--ErrorLevel-->
<GridViewColumn Header="" Width="45">
<GridViewColumn.CellTemplate>
<DataTemplate DataType="viewModel:MyViewModel">
<Image Source="{Binding Model.ErrorLevel, Converter={StaticResource ErrorLevelToImageConverter}, Mode=OneWay}"
ToolTip="{Binding Model.ErrorLevel, Mode=OneWay}" Width="20" Margin="5" VerticalAlignment="Top" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<!--ID-->
<GridViewColumn Header="ID">
<GridViewColumn.CellTemplate>
<DataTemplate DataType="viewModel:MyViewModel">
<TextBlock TextAlignment="Center" Margin="5" Width="50" VerticalAlignment="Top" >
<Hyperlink NavigateUri="{Binding Model.Hyperlink, Mode=OneWay}"
Command="{Binding HyperlinkCommand}">
<TextBlock Text="{Binding Model.Id, Mode=OneWay}" />
</Hyperlink>
</TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<!--Name-->
<GridViewColumn Header="Name" Width="500" >
<GridViewColumn.CellTemplate>
<DataTemplate DataType="viewModel:MyViewModel">
<Expander ToolTip="Expand" ExpandDirection="Down" Foreground="Black" VerticalAlignment="Top">
<Expander.Header>
<TextBlock Text="{Binding Model.Name, Mode=OneWay}"
HorizontalAlignment="{Binding HorizontalAlignment, RelativeSource={RelativeSource AncestorType=ContentPresenter}, Mode=OneWayToSource}"
TextAlignment="Left" Margin="5" TextWrapping="Wrap" VerticalAlignment="Top" />
</Expander.Header>
<GroupBox Header="Description" FontWeight="Bold" >
<TextBlock Text="{Binding Model.Description, Mode=OneWay}" TextWrapping="Wrap"
FontWeight="Normal" TextAlignment="Left" Margin="5" />
</GroupBox>
</Expander>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<!-- Module-->
<GridViewColumn Header="Module" >
<GridViewColumn.CellTemplate>
<DataTemplate DataType="viewModel:MyViewModel">
<TextBlock Text="{Binding Model.Module, Mode=OneWay}"
TextAlignment="Center" Margin="5" Width="100" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
</DockPanel>
Once again, i am new to WPF, MVVM, DataBinding and all this. So please try to make your answer as detailed as possible. I tried many things, but they didn't work out.
You could add the following GridViewColumn at the left side (top in XAML) to your GridView
<GridViewColumn Header="" Width="30">
<GridViewColumn.CellTemplate>
<DataTemplate DataType="viewModel:MyViewModel">
<Expander Margin="-5,2,-5000,0" HorizontalAlignment="Left" Width="{Binding Path=ActualWidth, RelativeSource={RelativeSource AncestorType={x:Type ItemsPresenter}}}">
<GroupBox Header="Description" FontWeight="Bold" Margin="0,0,5,0">
<TextBlock Text="{Binding Model.Description}" FontWeight="Normal" TextWrapping="Wrap" />
</GroupBox>
</Expander>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
This is GridViewColumncontains an empty Header which simply shows the Expander-Arrow in the GridViewRows.
The Expander itself is left aligned and has a huge negative Margin on the right side, so it can draw its content outside of the right boundary. The width is set to the ActualWidth of the ItemsPresenter of your GridView. With this Width you can limit the content to the current visible Width of the GridView (Or you can set it to an absolute value like 500).
And finally a preview of this Column
OK, the fact that the expander is not stretchable is because of the non stretchable parent control. You have a column 'Name' in your gridview with a fixed width and a expander added as a child. As far as i know the child control cannot extend beyond the parent control if this is not truth im sure someone will correct this. I don't know what the best way is to achieve your goal but to give you some inspiration i made a small example.
So, to give you a example if how this could work:
Edit: You can just set negative margins on your expander like so:
<Expander ToolTip="Expand" ExpandDirection="Down" Margin="-100,0,-300,0" Foreground="Black" VerticalAlignment="Top">
Thanks to #LittleBit for this tip.
<ListView x:Name="lsttest" ItemsSource="{Binding persons}">
<ListViewItem>
<StackPanel>
<ListView>
<ListView.View>
<GridView>
<GridViewColumn Header="#1" Width="50">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"
Width="20" TextAlignment="Left" Margin="5" VerticalAlignment="Top" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Test 2" Width="50">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"
Width="20" TextAlignment="Left" Margin="5" VerticalAlignment="Top" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
<Expander ToolTip="Expand" ExpandDirection="Down" Foreground="Black" VerticalAlignment="Top">
<Expander.Header>
<TextBlock Text="{Binding Model.Name, Mode=OneWay}"
HorizontalAlignment="{Binding HorizontalAlignment, RelativeSource={RelativeSource AncestorType=ContentPresenter}, Mode=OneWayToSource}"
TextAlignment="Left" Margin="5" TextWrapping="Wrap" VerticalAlignment="Top" />
</Expander.Header>
<GroupBox Header="Description" FontWeight="Bold" Width="{Binding ActualWidth, ElementName=lsttest}">
<TextBlock Text="{Binding Name, Mode=OneWay}" TextWrapping="Wrap"
FontWeight="Normal" TextAlignment="Left" Margin="5" />
</GroupBox>
</Expander>
</StackPanel>
</ListViewItem>
</ListView>
The result:
I have the following usercontrol to define my general control-layout:
<UserControl>
<DockPanel LastChildFill="False">
<ListView DockPanel.Dock="Left"
ItemsSource="{Binding FoundResults}"
SelectedItem="{Binding SelectedItem}"
ItemTemplate="{DynamicResource FoundResultsStyle}"/>
<ContentControl DockPanel.Dock="Top"
Name="WinSock"
Content="{Binding ElementName=BaseWindowUserControl, Path=SpecificView}" />
<StatusBar DockPanel.Dock="Bottom">
<StatusBarItem Content="{Binding StatusBarText, Mode=OneWay}" />
</StatusBar>
</DockPanel>
</UserControl>
Every window should have a ListView on the left side as you can see.
I need a way to define the ItemTemplate in the concrete userControl.
Person-Usercontrol:
<UserControl.Resources>
<DataTemplate x:Key="FoundResultsStyle" DataType="{x:Type Pocos:Person}">
<StackPanel>
<TextBlock Text="{Binding Lastname}"/>
<TextBlock Text="{Binding Firstname}"/>
</StackPanel>
</DataTemplate>
</UserControl.Resources>
The ListView doesn't use my Template which I have defined in my 'concrete' usercontrol. Is there a way to achieve this?
Thank you in advance!
Can you do something like this, so that the DataType, as it changes, will select the correct template?
<UserControl>
<UserControl.Resources>
<DataTemplate DataType="{x:Type Pocos:Person}">
...
</DataTemplate>
<DataTemplate DataType"{x:Type Pocos:Dog}">
...
</DataTemplate>
</UserControl.Resources>
<DockPanel LastChildFill="False">
<ListView
DockPanel.Dock="Left"
ItemsSource="{Binding FoundResults}"
SelectedItem="{Binding SelectedItem}"/>
<ContentControl
DockPanel.Dock="Top"
Name="WinSock"
Content="{Binding ElementName=BaseWindowUserControl, Path=SpecificView}" />
<StatusBar DockPanel.Dock="Bottom">
<StatusBarItem Content="{Binding StatusBarText, Mode=OneWay}" />
</StatusBar>
</DockPanel>
</UserControl>
This is my code of ContentPresenter:
<ListBox ItemsSource="{Binding Items}" BorderThickness="0" HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<ContentPresenter x:Name="PART_ValueContainer">
<ContentPresenter.Content>
<MultiBinding>
<Binding Path="Value"/>
<Binding Path="ReadOnly"/>
</MultiBinding>
</ContentPresenter.Content>
<ContentPresenter.Resources>
<DataTemplate>
<TextBox IsReadOnly="{Binding Path=Content.ReadOnly, RelativeSource={RelativeSource AncestorType={x:Type ContentPresenter}}}"
Text="{Binding Path=Content.Value, RelativeSource={RelativeSource AncestorType={x:Type ContentPresenter}}}"
TextAlignment="Left"/>
</DataTemplate>
</ContentPresenter.Resources>
</ContentPresenter>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I trying to fill the Text from object Items.Value and property IsReadOnly from Items.ReadOnly.
It doesn't work, I know that is not good solution, but, how to make something like that?
I have a ListView with an nested ItemTemplate for presenting orders.
Each order is presented within a Expander. These Expanders have a ContentTemplate for presenting all positions within each order. And these order positions are also in a Expander.
The ListView gets its data from an ObservableCollection (AvailableOrders) which contains all orders. These order object have a ObservableCollection "Items" holding all positions for this order.
But I'm not able to get the bindings work properly. How should I properly set the binding for the "inner expander" to show information about the items?
All ideas are appreciated!
<ListView ItemsSource="{Binding VMOrder.AvailableOrders}">
<ListView.ItemTemplate>
<DataTemplate>
<Expander Content="{Binding}">
<Expander.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Order " />
<TextBlock Text="{Binding Id}" />
</StackPanel>
</DataTemplate>
</Expander.HeaderTemplate>
<Expander.ContentTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.Template>
<ControlTemplate>
<Expander>
<Expander.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Material.Name}" />
</DataTemplate>
</Expander.HeaderTemplate>
<Expander.ContentTemplate>
<DataTemplate>
<TextBlock Text="TEST" />
</DataTemplate>
</Expander.ContentTemplate>
</Expander>
</ControlTemplate>
</ItemsControl.Template>
</ItemsControl>
</DataTemplate>
</Expander.ContentTemplate>
</Expander>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I've figured it out now.
I need to use a relative source in the data templates and set the content property of each expander.
<ListView ItemsSource="{Binding VMOrder.AvailableOrders}">
<ListView.ItemTemplate>
<DataTemplate>
<Expander Content="{Binding}">
<Expander.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Order " />
<TextBlock Text="{Binding DataContext.Id, RelativeSource={RelativeSource FindAncestor, AncestorType=Expander}}" />
</StackPanel>
</DataTemplate>
</Expander.HeaderTemplate>
<Expander.ContentTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Expander Content="{Binding}">
<Expander.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding DataContext.Material.Name, RelativeSource={RelativeSource FindAncestor, AncestorType=Expander}}" />
</DataTemplate>
</Expander.HeaderTemplate>
<Expander.ContentTemplate>
<DataTemplate>
<TextBlock Text="{Binding DataContext.Material.Description, RelativeSource={RelativeSource FindAncestor, AncestorType=Expander}}" />
</DataTemplate>
</Expander.ContentTemplate>
</Expander>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</Expander.ContentTemplate>
</Expander>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
For the inner ItemsControl, you have defined the control template for the whole control. You have to define the ItemTemplate instead
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Expander>
<Expander.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Material.Name}" />
</DataTemplate>
</Expander.HeaderTemplate>
<Expander.ContentTemplate>
<DataTemplate>
<TextBlock Text="TEST" />
</DataTemplate>
</Expander.ContentTemplate>
</Expander>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I'm writing application in windows phone 8 and have problem with bindings.
Here is my xaml code with my page structure
<phone:Pivot Grid.Row="1" SelectedIndex="{Binding SelectedPivotElement, Mode=TwoWay}" x:Name="SymbolsPivot" Title="Symbols" ItemsSource="{Binding CategoriesWithSymbols}">
<phone:Pivot.HeaderTemplate>
<DataTemplate>
<ContentControl Content="{Binding Name}"/>
</DataTemplate>
</phone:Pivot.HeaderTemplate>
<phone:Pivot.ItemTemplate>
<DataTemplate>
<telerikData:RadJumpList x:Name="SymbolsControl" ItemsSource="{Binding Path=Symbols}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
<telerikData:RadJumpList.GroupDescriptors>
<data:PropertyGroupDescriptor PropertyName="GroupName"
SortMode="Ascending" />
</telerikData:RadJumpList.GroupDescriptors>
<telerikPrimitives:RadDataBoundListBox.VirtualizationStrategyDefinition>
<telerikPrimitives:WrapVirtualizationStrategyDefinition Orientation="Horizontal"/>
</telerikPrimitives:RadDataBoundListBox.VirtualizationStrategyDefinition>
<telerikData:RadJumpList.GroupHeaderTemplate>
<DataTemplate>
<Grid Margin="0,-8,0,12" Width="480">
<TextBlock FontWeight="Bold" FontSize="{StaticResource PhoneFontSizeMedium}" Text="{Binding}" TextWrapping="Wrap"/>
</Grid>
</DataTemplate>
</telerikData:RadJumpList.GroupHeaderTemplate>
<telerikData:RadJumpList.ItemTemplate>
<DataTemplate>
<Grid Width="300">
<TextBlock Text="{Binding Symbol}"/>
</Grid>
</DataTemplate>
</telerikData:RadJumpList.ItemTemplate>
</telerikData:RadJumpList>
</DataTemplate>
</phone:Pivot.ItemTemplate>
</phone:Pivot>
<i:Interaction.Triggers>
<i:EventTrigger EventName="ItemTap" SourceName="SymbolsControl" >
<cmd:EventToCommand Command="{Binding TapCommand}"
/>
</i:EventTrigger>
</i:Interaction.Triggers>
So I have pivot control and inside pivot I have a list.
And now the problem is that application binds item tap event to my relay command but this event/command is never called. Everything works if I move list outside pivot. How to fix that problem ?