Since the Anniversary Update (Build 14383 / 14393) you should be able to toggle the visibility of XAML elements without using a converter, like this:
<TextBlock Text="I'm not visible!" Visibility="{x:Bind IsVisibleFalse}" />
<TextBlock Text="I'm visible!" Visibility="{x:Bind IsVisibleTrue}" />
I was trying this in my project, minimum target version set to Windows 10 Anniversary Edition. Unfortunately I did not get it to work.
This code works just fine:
<StackPanel Visibility="{x:Bind ViewModel.IsUnlocked,
Converter={StaticResource BoolToVisibilityConverter}, Mode=TwoWay}">
This one doesn't (no error on compile, just does not show up when the bool value changes):
<StackPanel Visibility="{x:Bind ViewModel.IsUnlocked}>
I suspect the Mode="TwoWay" to be the issue, as you can't set it "when the binding expression ends with a cast". This code does not work as well:
<StackPanel Visibility="{x:Bind ViewModel.IsUnlocked,
Converter={StaticResource BoolToVisibilityConverter}>
So my question is: Am I misssing something or is this not working yet in a MVVM-Scenario and only with code-behind?
The default Mode is OneTime, which renders your code not working. I suggest you use OneWay, which should be usable upon casting.
Turns out x:Bind defaults to Mode=OneTime - I mistakenly thought it's Mode=OneWay.
So this does actually work:
<StackPanel Visibility="{x:Bind ViewModel.IsUnlocked, Mode=OneWay}>
Related
I need help trying to understand why this is not working. According to MSDN, TemplateBinding is what should be used when binding the property of a control in a template to a property of the control implementing the template.
Except that Template Binding is not two-way. For two-way you need to use binding and then specify the relative source as TemplatedParent.
So I have the following XAML:
template
<ItemContainerTemplate x:Key="colHeaderTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}" VerticalAlignment="Center"/>
<ToggleButton Style="{StaticResource ToggleButtonStyle}" IsChecked="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=TwoWay, Path=(props:VisibilityHelper.IsGroupCollapsed)}"/>
</StackPanel>
</ItemContainerTemplate>
which is used here
<dxg:GridColumn x:Name="Total" Header="Total" FieldName="field1" Width="Auto" HorizontalHeaderContentAlignment="Center" props:VisibilityHelper.IsGroupCollapsed="False" HeaderTemplate="{StaticResource colHeaderTemplate}">
<dxg:GridColumn.EditSettings>
<dx:TextEditSettings HorizontalContentAlignment="Center"/>
</dxg:GridColumn.EditSettings>
</dxg:GridColumn>
The toggle button in the template must set a dependency property on the grid column. This works fine when the template is binding to a parent ie. the controls are nested,
I just can't figure out what I am doing wrong.
MSDN ref - http://msdn.microsoft.com/en-us/library/ms742882.aspx
One of the many SO posts about this - In WPF, why doesn't TemplateBinding work where Binding does?
Thank you
Right so I have found the solution. Firstly DataTemplate does work. As #Quercus, it is all in the binding to the correct control.
In my case not the GridColumn but the GridColumnHeader. So this
IsChecked="{Binding RelativeSource={RelativeSource AncestorType=dxg:GridColumnHeader}, Path=DataContext.(props:VisibilityHelper.IsGroupCollapsed)}"
works perfectly...when bound to the correct parent.
Also as #Quercus stated, the template is actually nested and that is why this works. I used a tool called Snoop which actually shows you the visual tree of the application and then the datacontext of the selected element. Using this I solved this issue as well as 2 others I was having.
I really hope this helps someone somewhere before everyone goes to MAUI or WinUI 3.
I´m trying to add a ButtonColumn to a TelerikDataGrid which was generated by the Windows Template Studio, without CodeBehind.
In a perfect world it would work like this, I think.
<tg:DataGridTemplateColumn x:Uid="Table_Open" >
<tg:DataGridTemplateColumn.CellContentTemplate >
<DataTemplate>
<Button x:Uid="Button_Open" Command="{x:Bind ViewModel.OpenCustomerCommand}"></Button>
</DataTemplate>
</tg:DataGridTemplateColumn.CellContentTemplate>
</tg:DataGridTemplateColumn>
This doesn't work, now I tried many opportunities but never reach the ViewModel.
I know in WPF it would work using
RelativeSource={RelativeSource AncestorType={x:Type UserControl},
But I don't get it reproduced in my UWP case.
I'm afraid you can't use x:bind to bind OpenCustomerCommand in DataTemplate, In general, if we want to bind viewmodel's OpenCustomerCommand we need set current Page DataContext as ViewModel then use binding markup extension to bind like the following.
<Button HorizontalAlignment="Right"
Margin="0,0,30,0"
Content="Favorite"
Command="{Binding ElementName=RootGrid,Path=DataContext.OpenCustomerCommand }"
/>
And this is the similar case that your could refer.
I am working on a project in WPF and I have a very strange case concerning my converters on a certain element.
In the following snippet:
<myCtl:Pager IsTabStop="False" Style="{StaticResource MainPager}"
DataContext="{Binding CurrentView, Converter={StaticResource SectionToPagerDriver}}"
Visibility="{Binding CurrentView, Converter={StaticResource SectionToVisibility}}"/>
The converter for 'DataContext' will fire, but the converter for 'Visibility' will not. This seems odd to me considering that they are both bound to 'CurrentView' which indeed changes. I have even tried setting the binding mode explicitly to 'TwoWay' but this does nothing to resolve the issue.
Does anyone have a clue why one binding would fire, and the other would not ?
When you set the DataContext on your Control, all other bindings will use the new object as their source.
If you check your output window, you'll see a binding error saying that there is no CurrentView property on whatever object is returned by that property.
Instead, you should just do:
<myCtl:Pager IsTabStop="False" Style="{StaticResource MainPager}"
DataContext="{Binding CurrentView, Converter={StaticResource SectionToPagerDriver}}"
Visibility="{Binding Converter={StaticResource SectionToVisibility}}"/>
I currently have a list of objects in which my RadGridView's ItemsSource is set to. When the property "DoNotContact" of the object in the list has been set to True, I want to hide the information in the cell that contains a Phone number within my RadGridView. As you can see in my XAML, I'm setting the Visibility property within the TextBlock like so:
<telerik:GridViewDataColumn Header="Evening" DataMemberBinding="{Binding Path=EveningPhone}" Width="75" SortMemberPath="EveningPhone">
<telerik:GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Visibility="{Binding Path=DoNotContact, Converter={StaticResource BoolToVisibilityConverter}}">
<Hyperlink Click="MakeEveningCallHandler">
<TextBlock Text="{Binding Path=EveningPhone}" />
</Hyperlink>
</TextBlock>
</DataTemplate>
</telerik:GridViewColumn.CellTemplate>
</telerik:GridViewDataColumn>
When attempting to debug it, the Converter is never hit and although I can see the property "DoNotContact" has been set, the phone number still shows. The converter itself works fine as I've used it in other occasions. Again I only want to hide the information WITHIN the cell for the "Evening" Property, not the actual column itself. Any Ideas what's going wrong here? Thanks a bunch!
The code you provided works for me!
I have defined a DataTemplate for a ListBox. Inside the template, I use TextBlock controls to display the properties of the data context. For example:
<TextBlock Text="{Binding Path=FirstName}" />
And if I do this:
<TextBlock Visibility="{Binding Path=IsAccountValid}" />
...the application runs, but there is a warning in the output about trying to bind a boolean property to a Visibility enumeration.
If I do this:
<TextBlock Visibility="{Binding Path=IsAccountValid,Converter={StaticResource visibilityOfBool}}" />
and somewhere in my App.xaml is:
<BooleanToVisibilityConverter x:Key="visibilityOfBool" />
I get a null reference exception.
I suspected this might be because the property IsAccountValid is not a dependency property, so I added a CheckBox to the window, and did this:
<TextBlock Visibility="{Binding Path=IsChecked,Converter={StaticResource visibilityOfBool},ElementName=butA}" />
But got the same error.
Why? The DataContext object is valid because if I bind IsAccountValid to the Text property, the value is correctly displayed.
The converter is never called, so I am wondering if it is the converter that cannot be found.
Why can the converter not be found? Why can the converter be found outside the data template and not inside the data template?
I tried building the template again with Blend, as Blend usually gets it right, but the code it generated was the same as mine.
I tried some of the fixes suggested on this website, including setting RelativeSource to TemplateParent and Self, but it made no difference.
What is going on?
We use such converter all the time in our Data Templates. Do you define the converter key inside your resource dictionary? Merge another Resource Dictionary?
The IsAccountValid property doesn't have to be a dependency property. If the converter couldn't be found then you wouldn't be able to open the form. You have the right approach using the converter but it is difficult to say exactly what is causing the exception without seeing more information.
As Amittai and Chris pointed out, it seems that you're headed in the right direction. I know it sounds a bit stupid, but try to add a space between the comma and the Converter= statement in the binding. Like so:
<TextBlock Visibility="{Binding Path=IsAccountValid, Converter={StaticResource visibilityOfBool}}" />
On some systems there are weird symptoms when there's no space after the comma. I couldn't find the actual reason for that.
Thank you all for your help in my investigation.
I have solved the problem.
These two lines of code are included in the DataTemplate, one is a TextBlock, and one is a hyperlink:
<TextBlock Text="Hello" Visibility="{Binding IsChecked,ElementName=chkBox,Converter={StaticResource visibilityOfBool}}" />
and
<TextBlock Grid.Column="1" >
<Hyperlink Click="ProgHomePageHyperlink_Click" >
<TextBlock Text="{Binding Path=Title}" />
</Hyperlink>
</TextBlock>
When they are both included in the code, the runtime throws a null reference exception.
But if I comment one of them out, either the TextBlock or the HyperLink, everything runs ok.
If I remove the Click handler from the hyperlink, everything runs ok.
If I comment out the converter in the TextBlock, the application runs, but I get a mismatched binding warning, which is well deserved.
So, including a Click handler in the hyperlink means the converter in the TextBlock cannot be found.
How weird is that!