WPF - simple relative path - FindAncestor - wpf

In the XAML below the ToolTip correctly binds to RelativeSource Self. However, I can't for the life of me work out how to get the TextBlock in the commented block to refer to SelectedItem.Description
<Controls:RadComboBoxWithCommand x:Name="cmbPacking"
Grid.Row="2"
Grid.Column="5"
ItemsSource="{Binding PackingComboSource}"
DisplayMemberPath="DisplayMember"
SelectedValuePath="SelectedValue"
SelectedValue="{Binding ElementName=dataGrid1, Path=SelectedItem.PackingID}"
ToolTip="{Binding RelativeSource={RelativeSource Self}, Path=SelectedItem.Description}"
IsSynchronizedWithCurrentItem="True"
Style="{StaticResource comboBox}">
<!-- <Controls:RadComboBoxWithCommand.ToolTip>-->
<!-- <TextBlock Text="{Binding RelativeSource={RelativeSource Self}, Path=SelectedItem.Description}" TextWrapping="Wrap" Width="50"/>-->
<!-- </Controls:RadComboBoxWithCommand.ToolTip>-->
</Controls:RadComboBoxWithCommand>
I would appreciate any suggestions
Thanks - Jeremy

It seems that since ToolTip does not have a parent, you need to bind to the placement target as below:
<Controls:RadComboBoxWithCommand Grid.Row="2"
Grid.Column="5"
ItemsSource="{Binding PackingComboSource}"
DisplayMemberPath="DisplayMember"
SelectedValuePath="SelectedValue"
SelectedValue="{Binding ElementName=dataGrid1, Path=SelectedItem.PackingID}"
IsSynchronizedWithCurrentItem="True"
Style="{StaticResource comboBox}">
<Controls:RadComboBoxWithCommand.ToolTip>
<ToolTip DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget}">
<TextBlock Text="{Binding SelectedItem.Description}"
TextWrapping="Wrap"
Width="100" />
</ToolTip>
</Controls:RadComboBoxWithCommand.ToolTip>
</Controls:RadComboBoxWithCommand>
Hope this is useful for someone
Jeremy

A relative source of self means the current object, which would be the TextBox itself in this particular case. You want a relative source of find ancestor with an ancestor type of RadComboBoxWithCommand. Alternatively, and perhaps a little simpler, is to give the combo box a name and use ElementName in your binding instead of a relative source:
<ComboBox x:Name="cb" ...>
<ComboBox.ToolTip>
<TextBlock Text="{Binding SelectedItem.Description, ElementName=cb}" .../>

Related

How can I make a control in Wpf depend on a property in viewmodel?

I have this codes, but I don't want just make control visible or invisible , I don't want to create it, because it works in background and does some work that takes time and I don't want it. how can I do that? Can I use if condition in xaml in wpf? I've heard about triggers but I don't know how to do that in my example?
<ContentControl Content="{Binding ViewService[NoteSaveView]}" Visibility="{Binding ViewModeVisibility[Insert]}"/>
<telerik:RadTabControl TabOrientation="Horizontal" TabStripPlacement="Right" Padding="5" BorderThickness="0" Margin="0 -5 -5 -5" Visibility="{Binding ViewMode,Converter={StaticResource UpdateViewToVisibility}}">
<telerik:RadTabItem Header="صفحه اصلی" Content="{Binding ViewService[NoteSaveView]}"/>
<telerik:RadTabItem Header="تاریخچه" Content="{Binding ViewService[LogView]}"/>
</telerik:RadTabControl>
Edit:
finally I solved my problem with this code:
<ContentControl>
<ContentControl.Content>
<MultiBinding Converter="{StaticResource ViewModeVisibilityToContent}">
<Binding Path="ViewModeVisibility[Insert]"/>
<Binding Path="ViewService[NoteSaveView]"/>
</MultiBinding>
</ContentControl.Content>
</ContentControl>
You could use a DataType property of a DataTemplate and then assign a data object to the property to activate a DataTemplate or null to deactivate it.
In the code below you just need to set PropertyInViewModel of type object in viewmodel to some int to activate the DataTemplate, or to null to deactivate it.
<StackPanel xmlns:System="clr-namespace:System;assembly=mscorlib">
<StackPanel.Resources>
<DataTemplate DataType="{x:Type System:Int32}">
<TextBox Text="{Binding Mode=OneWay}" Foreground="Beige" Background="Brown" Height="20" Width="50"/>
</DataTemplate>
</StackPanel.Resources>
<ContentControl Content="{Binding PropertyInViewModel}"/>
</StackPanel>

Why title is not saved in the database - WPF/Telerik/RadGridView?

I have this RadComboBox placed inside a RadGridViewDataColumn:
<tk:RadGridView
Name="grdPeople"
ItemsSource="{Binding People}"
SelectedItem="{Binding SelectedPerson, Mode=TwoWay}">
<tk:GridViewDataColumn
DataMemberBinding="{Binding PeopleDetails}"
UniqueName="PeopleDetails"
Header="People">
<tk:GridViewDataColumn.CellTemplate>
<TextBlock
Text="{Binding Title}"/>
</tk:GridViewDataColumn.CellTemplate>
<tk:GridViewDataColumn.CellEditTemplate>
<tk:RadComboBox
DisplayMemberPath="TitleValue"
SelectedItem="{Binding Path=People.Title, Mode=TwoWay}"
ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type tk:RadGridView}}, Path=DataContext.Titles}"/>
</tk:GridViewDataColumn.CellEditTemplate>
</tk:GridViewDataColumn>
</tk:RadGridView>
I know that the problem comes with mixing of the RadGridView and the window data context objects, but not sure, why title doesn't get saved in the DB?
On the contrary, if I replace the RadComboBox with ordinary TextBox:
<TextBox
Width="50"
Text="{Binding Title}"
TextAlignment="Left"/>
Typing the value in a text box works just fine, saving the title in the DB.
I am guessing its, something with mixing the various components in the cell edit template of RadGridView?
Just change the Path of SelectedItem binding from 'People.Title' to 'Title'
<tk:RadComboBox
DisplayMemberPath="TitleValue"
SelectedItem="{Binding Path=Title, Mode=TwoWay}"
ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type tk:RadGridView}}, Path=DataContext.Titles}"/>

WPF, XAML, FindAncestor binding DataTemplate/ControlTemplate hierarchy

We have the following XAML:
<DataTemplate x:Key="PictureMediaEditorInformationTemplate" DataType="mediaEditorInformation:PictureMediaEditorInformation">
<dxlc:LayoutGroup Orientation="Horizontal">
<dxlc:LayoutItem Label="{Binding LabelContent}">
<dxlc:LayoutGroup Orientation="Vertical">
<dxlc:LayoutItem Label="{Binding LabelTitle}" LabelPosition="Left">
<dxe:TextEdit EditValue="{Binding Title, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</dxlc:LayoutItem>
<dxlc:LayoutItem>
<dxe:ImageEdit ShowLoadDialogOnClickMode="Empty" ShowBorder="true" AllowDrop="True" Drop="PictureEditor_OnDrop"
Source="{Binding VisibleImage, Converter={StaticResource LexImageToImageConverter},
Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="320" Height="320" ShowMenu="true">
<dxmvvm:Interaction.Behaviors>
<dxmvvm:EventToCommand EventName="MouseDoubleClick" Command="{Binding ViewPictureCommand}"/>
</dxmvvm:Interaction.Behaviors>
<dxe:ImageEdit.MenuTemplate>
<ControlTemplate>
<StackPanel Orientation="Horizontal">
<dxe:ImageEditClearToolButton ImageSource="{Binding ButtonImage, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=dxlc:LayoutGroup}}"/>
And we can't work out the correct way to specify the DataTemplate datacontext for the ImageSource binding. It might be complicated by the fact that the DataTemplate is a resource instantiated in code using:
var template = (DataTemplate) lg.FindResource(item.DataTemplateName);
var uiElement = template.LoadContent() as FrameworkElement;
We've tried various things but with no success so far. I had hoped that setting uiElement.Name could be used in conjunction with ElementName but it fails presumably because it's crossing from a ControlTemplate to a DataTemplate.
NB:In the actual code the property is not called 'Wibble' :)
The solution was to specify a path in the binding:
<dxe:ImageEditClearToolButton ImageSource="{Binding Path=DataContext.Wibble}"

Removing duplicated XAML code by using custom control?

What is a good way to get rid of repeating XAML in different files. Example :
<StackPanel Grid.Row="8" Grid.Column="2" Style="{StaticResource ViewContentStyle}" Visibility="{Binding Type, Converter={StaticResource TypeToVisibility}}">
<ctl:NewLabel LabelContent="{x:Static common:LocalResources.UNameLabel}" LabelStyle="{DynamicResource ContentLabelStyle}"
ImageStyle="{DynamicResource ViewContentControlStyle}">
<ctl:ETextBox x:Name="UserName" HorizontalAlignment="Left" Style="{StaticResource {x:Type TextBox}}"
LostFocus="Textbox_OnLostFocus"
Text="{Binding Path=UserName, UpdateSourceTrigger=PropertyChanged, NotifyOnValidationError=True, ValidatesOnDataErrors=True}">
</ctl:ETextBox>
</ctl:NewLabel>
</StackPanel>
<StackPanel Grid.Row="9" Grid.Column="2" Style="{StaticResource ViewContentStyle}" Visibility="{Binding SelectedAuthenticationType, Converter={StaticResource AuthToVisibility}}">
<StackPanel Orientation="Horizontal" KeyboardNavigation.TabNavigation="None">
<Label Style="{DynamicResource ContentLabelStyle}" Content="{x:Static common:LocalResources.UPasswordLabel}"/>
<AdornerDecorator>
<PwdBox x:Name="Password"
HorizontalAlignment="Left"
LostFocus="Textbox_OnLostFocus" PasswordChar="*"
</PwdBox>
</AdornerDecorator>
</StackPanel>
I have 3 files where almost the same code is reused. I think there is a way to get rid of this by using a common custom control. However, I dont see much examples as to how it can be done. Any leads would be great.
Add a new UserControl to your project and move the common XAML to this one.
You could then create an instance of this UserControl (replace "UserControl1" with the actual name of your UserControl) in any other view:
<!--insert the shared markup here: -->
<local:UserControl1 />

Adding custom values to ComboBox with CompositeCollection

I'm new to WPF. I have a combobox which when choosing a value three other fields (AbbrBlock, MultiBrandSupplier, IgnoreNoCompetition) update along to show the correct relevant values according to the data source. No problem with this.
Issue arises when I try to add to the combobox a custom value, although the combobox shows all values correctly, the other fields don't change when changing the combobox's value.
Here's the working code (without the additional custom combobox value - stripped to the key pieces):
<Window.Resources>
<local:OrdersDataSet x:Key="ordersDataSet" />
<CollectionViewSource x:Key="caSuppliersViewSource" Source="{Binding CaSuppliers, Source={StaticResource ordersDataSet}}"/>
</Window.Resources>
...
<StackPanel DataContext="{StaticResource caSuppliersViewSource}">
<ComboBox Name="SupplierDropdown" DisplayMemberPath="SupplierName"
ItemsSource="{Binding Source={StaticResource ResourceKey=caSuppliersViewSource}}"/>
<TextBlock Name="AbbrBlock" VerticalAlignment="Center" Text="{Binding Abbr}"/>
<CheckBox Name="MultiBrandSupplier" IsChecked="{Binding MultiBrand}"/>
<CheckBox Name="IgnoreNoCompetition" IsChecked="{Binding IgnoreNoCompetition}"/>
</StackPanel>
Here's the code with the added custom value which shows correctly but the other fields don't update when changing the combobox value:
<Window.Resources>
<local:OrdersDataSet x:Key="ordersDataSet" />
<CollectionViewSource x:Key="caSuppliersViewSource" Source="{Binding CaSuppliers, Source={StaticResource ordersDataSet}}"/>
</Window.Resources>
...
<StackPanel DataContext="{StaticResource caSuppliersViewSource}">
<StackPanel.Resources>
<CompositeCollection x:Key="myCompositeCollection">
<CollectionContainer Collection="{Binding Source={StaticResource ResourceKey=caSuppliersViewSource}}" />
<ComboBoxItem Content="Add New..." />
</CompositeCollection>
</StackPanel.Resources>
<ComboBox Name="SupplierDropdown" DisplayMemberPath="SupplierName"
ItemsSource="{Binding Source={StaticResource myCompositeCollection}}"/>
<TextBlock Name="AbbrBlock" VerticalAlignment="Center" Text="{Binding Abbr}"/>
<CheckBox Name="MultiBrandSupplier" IsChecked="{Binding MultiBrand}"/>
<CheckBox Name="IgnoreNoCompetition" IsChecked="{Binding IgnoreNoCompetition}"/>
</StackPanel>
What am I missing here?
Looks like the ComboBox was updating caSuppliersViewSource's View.CurrentItem property (I think) to match its SelectedItem in your first snippet. In the second, the CollectionViewSource is buried inside a CompositeCollection so that doesn't happen any more. However, the ComboBox is still selecting an item, and you can just bind to that using ElementName. No need for setting the DataContext on the StackPanel with this version.
<StackPanel>
<StackPanel.Resources>
<CompositeCollection x:Key="myCompositeCollection">
<CollectionContainer Collection="{Binding Source={StaticResource ResourceKey=caSuppliersViewSource}}" />
<ComboBoxItem Content="Add New..." />
</CompositeCollection>
</StackPanel.Resources>
<ComboBox
Name="SupplierDropdown"
DisplayMemberPath="SupplierName"
ItemsSource="{Binding Source={StaticResource myCompositeCollection}}"
/>
<TextBlock
Name="AbbrBlock"
VerticalAlignment="Center"
Text="{Binding SelectedItem.Abbr, ElementName=SupplierDropdown}"
/>
<CheckBox
Name="MultiBrandSupplier"
IsChecked="{Binding SelectedItem.MultiBrand, ElementName=SupplierDropdown}"
/>
<CheckBox
Name="IgnoreNoCompetition"
IsChecked="{Binding SelectedItem.IgnoreNoCompetition, ElementName=SupplierDropdown}"
/>
</StackPanel>
You could also give eyour viewmodel a SelectedDBItem property of the same type as whatever caSuppliersViewSource contains, and bind ComboBox.SelectedItem to that. Then you could do this:
<TextBlock
Name="AbbrBlock"
VerticalAlignment="Center"
Text="{Binding SelectedDBItem}"
/>
But that's six dozen of one, half of another, or something -- unless you want to do something else with SelectedDBItem in your viewmodel, then it's handy.

Resources