views:

42

answers:

2

Hi all,

I have a problem. I made a template for a TreeView and I need to set the initial value of the ToggleButton's IsChecked property depending on my model. But it turns out that setting this property using triggers/setters disables the databinding.

Is it so? If yes, give me a suggestion how it can be fixed?

<DataTemplate x:Key="CellTemplate_Name">
   <DockPanel x:Name="dock">
      <ToggleButton x:Name="Expander"
        IsChecked="{Binding Path=IsExpanded, RelativeSource={RelativeSource AncestorType={x:Type TreeViewItem}}}"> <--- Binding
    ...
      <ToggleButton/>
    ...
   <DataTemplate.Triggers>
      <DataTrigger Binding="{Binding Path=ObjIsOpened, Converter={StaticResource DebugConverter}}" Value="true"> <--- Trigger
         <Setter TargetName="Expander" Property="IsChecked" Value="true"></Setter>
      </DataTrigger>
                    ...
   </DataTemplate.Triggers>
</DataTemplate>

Regards, Lerax.

+1  A: 

Hi Lerax,

I suspect they do not disable data binding, they just have higher priority. Instead of using binding and trigger at the same time, why don't you use one of them (either binding or trigger)? E.g. you could bind to model directly, and don't use trigger at all...

Anvaka
Yes, the best solution is derect binding to the model, but I already bind that property to another one. Is it possible to bind more than two properties together? Id if yes, how can it be done in XAML? I've just found somethig aboud MultiBinding.
Yes, there is MultiBinding. But why would you use it if you can set value from model? Model knows current state, right (e.g. object was just created, it should be expanded.)?
Anvaka
The problem is that I use my own ToggleButton istead of standard Expander of TreeView and they must by binded together. In addition I need to set the initial value for both of them. Therefore, I need to bind three differen properties. Is it correct?
Yes and no :). If you want to have your own expander INSTEAD of original, then you've chosen wrong place for it. Refer to Aviad's answer. That's the right way to follow.
Anvaka
I know that I can style the original one, but in my case it is not possible because the original expander must be hidden. The only way for me is to create a ToggleButton on the position I need and to bound it to the hidden expander. That is why, I think MultiBinding is the best sollution for me. However, I will try to redesigne my control and let you know about my progress. =) Thanx!
Sure :). You may also post a visual sketch of what you are trying to achieve. That may help us to propose a better solution.
Anvaka
+2  A: 

First of all I suggest you read the excellent article by Josh Smith Simplifying the WPF TreeView by Using the ViewModel Pattern

Based on that article, I would suggest defining a style for the TreeViewItem (using the ItemContainerStyle property of the TreeView) which binds its IsExpanded property to your model object's ObjIsOpened property. Then get rid of your trigger.

Example:

<Style TargetType="TreeViewItem">
    <Setter Property="IsExpanded" 
        Value="{Binding ObjIsOpened, Converter={StaticResource DebugConverter}}"/>
</Style>

<DataTemplate x:Key="CellTemplate_Name">
   <DockPanel x:Name="dock">
      <ToggleButton x:Name="Expander"
        IsChecked="{Binding Path=IsExpanded, 
                       RelativeSource={RelativeSource 
                           AncestorType={x:Type TreeViewItem}}}"> <--- Binding
    ...
      <ToggleButton/>
    ...
</DataTemplate>
Aviad P.
Hi Aviad. Thank you for the answer, it works very good. But it doesn't modify the ObjIsOpened value in my model. So, if ObjIsOpened=true by defaul, each TreeViewItem becomes expanded after refresh. I think MultiBinding could help? What do you think?
What is the problem exactly, that clicking the toggle button doesn't change ObjIsOpened, or that changing ObjIsOpened in code doesn't affect the GUI? If the former, try adding `Mode=TwoWay` to the binding, if the latter you must implement some kind of change notification in your model, the most common way is to implement `INotifyPropertyChanged` on your class and whenever ObjIsOpened is set, fire that event.
Aviad P.
My bad... "Mode=TwoWay" fixes the problem.