I have a WPF UserControl that's housed in an element host on a WindowsForms.
The WPF UserControl contains a ListBox that uses a DataTemplate that has a data bound to aTextBlock:
<UserControl.Resources>
<DataTemplate x:Key="NewsListBoxTemplate">
<TextBlock Name="tbTemplate" Padding="30,0" FontSize="28"
Text="{Binding Path=newsE}" Foreground="Blue"/>
</DataTemplate>
</UserControl.Resources>
The DataContext is based on a DataSet that gets its data from a sql server database.
I've researched and seen the various answers on SO and can identify the TextBlock at run time. But what I want to do is to change the Binding Path for that TextBlock to point to a different field of the DataSet when the user makes a choice on the Windows Form at runtime.
There are only two database fields available as choices.
From the point where I've identified the TextBlock name as tbTemplate, can anyone suggest code I can use to switch between the two Paths?
You can use BindingOperations
BindingOperations.SetBinding(tbTemplate, TextBlock.TextProperty, new Binding("MyProperty"));
Follow the link.. to get the control with its name from the DataTemplate and do the binding for that...
tbTemplate.SetBinding(TextBlock.TextProperty, new Binding("PropertyName"));
Related
I got the following setup for my page:
<ListView ItemsSource="{Binding RecentResults}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid Background="Transparent" Orientation="Horizontal" ItemWidth="400" ItemHeight="300" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<ui:CarResultControl Result="{Binding}" Padding="0" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I bind to a local property which provides my results asynchronously. This works perfectly fine.
Now my CarResultControl binds to it's local Result property (which is an DependencyProperty). When I specify Result={Binding} then the property get's updated but not as expected with the CarResult but CarResultControl. If I use Result={Binding Path=.} or similiar, it just doesn't update at all.
As far as I'm used to it in WPF {Binding} actually bound to the data object itself, not the control you´re attaching the binding to. Interesting is that IntelliSense actually shows the properties of the expected CarResult object when I have to choose a binding path for Result.
Is UWP doing it's own thing here again, am I just a fool and doing it wrong or is this really a bug? I struggled for long enough and can't find any info about it.
This actually should be working the way you expect unless you are changing the DataContext of the CarResultControl.
UserControls actually work in a bit weird way - when you set this.DataContext = this in the constructor, then the binding on properties will actually be relative to the UserControl itself.
To fix this you must make sure not to change the DataContext of the control itself. The easiest way is to add x:Name to the root Grid (or whatever control you have in the content of the UserControl and then set its DataContext:
RootGrid.DataContext = this;
This way you will the data context of the RootGrid will be set to the control itself, but the user control's properties will be bound to the data context relative to where the user control is, here to the list item.
In my WPF app we are using an adorner for displaying validation messages, in the particular case there is a single row grid that has multiple controls some of which have validation. The problem I'm having is that I want to force the width of the error message control to be the same as the grid but can't seem to find a way to reference that grid from the adorner template. Here is a sample of what I tried:
<ControlTemplate x:Key="Local_TopAdornedTemplateWide">
<StackPanel>
<AdornedElementPlaceholder x:Name="adornedElement"/>
<TextBlock MaxWidth="{Binding Path=ActualWidth, RelativeSource={RelativeSource FindAncestor, AncestorType=Grid}, ElementName=adornedElement}"
TextWrapping="Wrap"
Text="{Binding Converter={StaticResource Local_ValidationErrorMessageConverter}}"
Style="{DynamicResource Error_Text}"
Padding="2 1 0 0"
Visibility="{Binding ElementName=adornedElement, Mode=OneWay, Path=AdornedElement.IsVisible, Converter={StaticResource BooleanToVisibilityConverter}}"
/>
</StackPanel>
</ControlTemplate>
This causes the application to crash with an XamlParseException.
Ideally the solution would not be specific to a grid so that it would get the width of any container type, but for now grid is the only use case.
Edit:
Here is an example of another template we use in the application; this template would not work for my case as it would limit the error to be the width of a single column of the aforementioned grid:
<ControlTemplate x:Key="Local_TopAdornedErrorTemplate">
<StackPanel>
<AdornedElementPlaceholder x:Name="adornedElement"/>
<TextBlock MaxWidth="{Binding ElementName=adornedElement, Path=ActualWidth}"
TextWrapping="Wrap"
Text="{Binding Converter={StaticResource Local_ValidationErrorMessageConverter}}"
Style="{DynamicResource Error_Text}"
Padding="2 1 0 0"
Visibility="{Binding ElementName=adornedElement, Mode=OneWay, Path=AdornedElement.IsVisible, Converter={StaticResource BooleanToVisibilityConverter}}"
/>
</StackPanel>
</ControlTemplate>
Using snoop I captured the following two screenshots (I could not take one of the full stack to prevent posting anything proprietary)
This shot shows the grid I mentioned previously, within this it is the FinancialTextBox item that is being adorned
This shot shows two things, the item selected in blue is the highest ancestor of the grid in the previous shot, the yellow highlight is the Textbox from the content template
With those two it seems to be apparent that (based on information from Contango's answer) the two items aren't not in the same visual tree which would lead me to believe my question is not possible. However the second template I added (which does work) points that at least some visual information from the adorned element lives on in the place holder.
So now my question boils down to a) does this information include the parent of the adorned element and b) how can this be accessed via a binding on a different element?
This ended up being a lot simpler than the path I was trying to go down.
I was doing some reading on the AdornedElementPlaceholder class and came across this entry on MSDN and noticed that the class actually has a property called parent, with that I tried the following binding and it works perfectly:
MaxWidth="{Binding ElementName=adornedElement,
Mode=OneWay,
Path=AdornedElement.Parent.ActualWidth}"
WPF is quite powerful and flexible.
You can bind any property in any XAML tag to any property in any other XAML tag.
For example, you could write a test app that binds the Text property of an input box to the Text property of a label, so as you type something into the text box, the label would change automatically (assuming you use UpdateSourceTrigger=PropertyChanged). This is a direct XAML to XAML binding, with no C# in sight.
Similarly, you could bind the width of your error box to the width of the parent control, whatever that may be.
Google RelativeSource and AncestorType, this is a great link:
http://druss.co/2013/10/wpf-binding-examples/
See if you can grok how the Visual Tree and Logical Tree works in WPF, once you understand that, you will understand more of how binding works.
I'd also recommend using the free tool Snoop to look at the Visual Tree. XAML Spy is excellent, but not free.
Snoop can tell you if there is anything that has a bad binding at runtime (you set the filters up, and it will list all bad bindings).
You can use Snoop to get the full XAML path of your source (the XAML you wrote above), then get the full XAML path of the target (i.e. the ActualWidth of your Grid), then compare them: it may be quickly apparent that one is not the ancestor of the other, as they are on different branches of the visual tree, or that there is some other issue which is preventing a simple walk up the visual tree from working.
If you just want to get something working, as a proof of concept, try naming the target XAML grid using x:Name, and reference it by name instead of AncestorType.
I am trying to create a TreeView that allows child nodes of types textBlock and comboBox. Here is a picture of what this would look like:
I believe that this is an issue that can be solved by using a HierarchicalDataTemplate because the xaml is the area of the code that I would specify what UI control I cam using. So far I have tried implementing a StackPanel with my HierarchicalDataTemplate like so:
<HierarchicalDataTemplate DataType="{x:Type data:DataModel}" ItemsSource="{Binding Children}">
<StackPanel>
<TextBlock Text="{Binding DisplayName}" />
<ComboBox ItemsSource="{Binding CommandCollection}" />
</StackPanel>
</HierarchicalDataTemplate>
But I do not achieve the correct solution with this because StackPanel is basically setting up each node so that they contain both a textBlock and a comboBox. This is a problem because each child node is either a textBlock or a comboBox, never both. How do I set up a HierarchicalDataTemplate that allows TreeView child nodes to be either textBlocks or comboBoxes? Please let me know if you would like more details on how my TreeView is implemented, or would like to see more code.
Some background references to this question can be found here, and here.
Usually it is a good idea to template different types of data with respective data templates. This can be achieved implicitly by placing the templates in the TreeView.Resources and using the DataTemplate.DataType property.
Here is an example: [Link]
The only thing that differs is that you would use a hierarchical template and bind the ItemsSource of the template respectively to a property containing child items.
I'm using a telerik RadGridView which is pretty much the same thing as a normal DataGrid in WPF. In my gridview.columns I have a GridViewDataColumn which then allows me to put a celltemplate then a datatemplate and then allow me to put different controls within a grid. I have a combobox and a textbox(only one shows at a time based on visibility property). The problem I'm having is the tab system is kind of weird and doesn't work right. When I tab to a cell in the column above, my combobox nor my textbox ever gets focus. In fact the cell turns completly white. So I was wondering how (in code behind) can I detect when a user tabs in this particular cell and manually set focus to these child elements inside this cell on the selected row?
<telerik:GridViewDataColumn x:Name="MyDataColumn" Focusable="True" GotFocus="MyDataColumn_GotFocus_1" Header="Header1" Width="250">
<telerik:GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<Textbox x:name="MyTextbox" Visibility="{Binding IsTextbox}"/>
<Combobox x:name="MyCombobox" Visibility="{Binding IsCombo}"/>
</Grid>
</DataTemplate>
</telerik:GridViewColumn.CellTemplate>
</telerik:GridViewDataColumn>
*Basically, how can I gain access to one of those child controls inside this GridViewDataColumn in code behind so that I can set focus to it? Thanks so much for any advice.
Probably the most straight forward answer to your question can be found by reading the answer to the Access items inside the DataTemplate in WPF post.
However, it may be worth reading the correct answer in this Access Elements inside a DataTemplate… How to for more than 1 DataTemplate? post also.
It's my xaml:
<Custom:DataGridTemplateColumn Header="Pilih" Width="50" IsReadOnly="False">
<Custom:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox Height="23" Name="ckPilih" Checked="ckPilih_Checked">
</CheckBox>
</DataTemplate>
</Custom:DataGridTemplateColumn.CellTemplate>
</Custom:DataGridTemplateColumn>
when i want to use it(ckPilih) in .cs it can't access
You won't have direct access to this checkbox in code behind because the scope of ckPilih is only inside the DataTemplate
On the side note, I am not sure about your use case but it is not usually recommended to access the checkbox or any other control inside DataTemplate in this manner. You should always try to bind the DataGrid with your datasource. DataGrid will then automatically reflect the changes in DataSource
It is DataTemplate element. you can access it only in your DataTemplate definition. Instead of this, you should use DataGrid.Rows[i].Cell[j].Children property to access collection of controls in a cell.