Results 1 to 7 of 7

Thread: [RESOLVED] WPF Binding Issue

  1. #1

    Thread Starter
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    39,376

    Resolved [RESOLVED] WPF Binding Issue

    I have a form that has a case where DataContext is set to some object in the constructor:
    Code:
    private mFoo as Bar
    private mBarList as New List(of Bar)
    
    Public sub New()
    mBarList(mFoo)
    mBarList(New Bar)
    
    Me.DataContext = mFoo
    
    End Sub
    This is somewhat contrived. The constructor is actually given the list of Bar rather than it being constructed, but that doesn't matter for this example. The point is that there is a list of Bar, mFoo is in that list, but mFoo is also a private variable at form scope.

    In the XAML, I have a datatrigger like so:

    Code:
    <DataTrigger Binding="{Binding Path=SomePropertyofFoo, Mode=OneWay}" Value="1">
        <Setter Property="Background" Value="green"></Setter>
    </DataTrigger>
    There are a couple other, similar data triggers, as what I am doing with this is changing the background color of some buttons based on a property of Foo.

    This works up to a point. However, there are Back and Next buttons, which swap mFoo for a different Bar in the list, as one might expect. The user can iterate through all the Bar in the list, each one being put into mFoo in turn.

    The swapping works, but that datatrigger does not. I can confirm that pressing any of the buttons does what it should, and uses the new mFoo (which it pretty much has to, since that part isn't using binding), but the color of the buttons remains the same. It certainly looks like the binding is sticking with not the contents of mFoo, but with whichever object in the mBarList set that it was originally bound to.

    Basically, it's binding to the actual object, not to 'the object whose reference is held in the mFoo variable'. In other words, it stays bound to the same object even when the object in the variable changes.

    I can live with this, but I'm wondering if that is, indeed, the case, and whether there is a simple fix for this. It would have to be simple, though, because there IS a simple fix that can solve this problem by getting rid of the datatriggers and changing the colors in code. So, what I'm really looking for as a solution is a way to deal with this and still use the XAML approach for this coloring.
    My usual boring signature: Nothing

  2. #2
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,703

    Re: WPF Binding Issue

    Haha. I didn't expect someone of your experience to make this kind of mistake . It doesn't matter if you change what mFoo is pointing to that doesn't change the reference Me.DataContext has to the object.

    Based on what you described, you're doing something like this:-
    Code:
            Dim a As New TextBox With {.Text = "Hello"}
    
            Me.Tag = a
    
            a = New TextBox With {.Text = "World"}
    
            'Prints "Hello" because Tag holds a reference to the
            'old TextBox
            Debug.WriteLine(DirectCast(Me.Tag, TextBox).Text)
    You have to change the DataContext property, not mFoo.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  3. #3
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,703

    Re: WPF Binding Issue

    Now, looking at this closely, I think it's pretty clear what you're trying to do. You want to make it so that when you change the Form scoped mFoo to another object, the data-bound elements would reflect these changes. If this is what you want, you have to bind DataContext to mFoo. It's not too hard but it would take a bit of effort. I'll just show you with an example. Lets start with the XAML:-
    Code:
    <Window x:Class="MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:DataContextTest"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800">
        <Grid >
    
            <Grid.Resources>
                <Style x:Key="ftrig" TargetType="TextBlock">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding RateValue}" Value="1">
                            <Setter Property="Background" Value="Blue"/>
                        </DataTrigger>
    
                        <DataTrigger Binding="{Binding RateValue}" Value="2">
                            <Setter Property="Background" Value="Red"/>
                        </DataTrigger>
    
                        <DataTrigger Binding="{Binding RateValue}" Value="3">
                            <Setter Property="Background" Value="DarkGreen"/>
                        </DataTrigger>
    
                    </Style.Triggers> 
                    
                </Style>
            </Grid.Resources>
    
            <StackPanel DataContext="{Binding CurrentRating}" >
                <TextBlock Style="{StaticResource ftrig}" >Hello world</TextBlock>
                <Button Click="Button_Click" >Press me</Button>
            </StackPanel>
            
            
        </Grid>
    </Window>
    Pay attention to what I highlighted in red. That is binding the DataContext property of the StackPanel to CurrentRating which is a property of the Window itself, much like mFoo in your contrived sample. The TextBlock within the StackPanel will change colours based on what is assigned to the CurrentRating property of the Form itself. Now let's look at the code-behind:-
    Code:
    Imports System.ComponentModel
    Imports System.Net.Security
    
    Class MainWindow
        Implements INotifyPropertyChanged
    
        Private _CurrentRating As Rating
    
        Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
    
        Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
    
            'We want the children of this Window
            'to be able to bind to our CurrentRating property
            'So we set the DataContext of the Window to itself
            Me.DataContext = Me
        End Sub
    
        Public Property CurrentRating As Rating
            Get
                Return _CurrentRating
            End Get
            Set
                _CurrentRating = Value
    
                'This allows to alert WPF's binding system when this property has
                'been assigned a new object
                RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(NameOf(Me.CurrentRating)))
            End Set
        End Property
    
        Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
    
            'The DataTrigger would recognize when this has changed
            If Me.CurrentRating Is Nothing Then
                Me.CurrentRating = New Rating(1)
            Else
                Me.CurrentRating = New Rating((Me.CurrentRating.RateValue Mod 3) + 1)
            End If
    
        End Sub
    End Class
    Public Class Rating
    
        Public Sub New(ByVal rateValue As Integer)
            Me.RateValue = rateValue
        End Sub
    
        Public Property RateValue As Integer
    
    End Class
    I highlighted the important things in red. One, the DataContext property of the Window is set to itself. This way the DataContext property of it's child StackPanel can bind to the CurrentRating property. The other thing that was important is the implementation of INotifyPropertyChanged on the Form itself. This is necessary so that when you change the reference of CurrentRating, the data-binding system would be aware of it so that the DataTriggers can work.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  4. #4

    Thread Starter
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    39,376

    Re: WPF Binding Issue

    Ah, I see what you're doing.

    I was expecting it to handle the binding in a way similar to the odd way that hooking up event handlers works with the Handles clause. You can have some variable declared WithEvents. That variable, being a reference type, holds nothing but a reference to some object, just as my mFoo holds a reference to some object. If you have a bunch of Handles clauses, you can swap the variable around and the event handlers will work fine. I expected similar behavior for WPF binding, since it was bound to a reference type.

    I think I'll just abandon the binding for this. It's good to know how I could have done it, but it's three buttons on a complicated form, and the only thing I am doing is coloring the buttons.

    Binding is an amazing, powerful, and versatile part of XAML, but it's not always worth it. Those datatriggers can be cool, or they can be overly wordy. This is a case of overly wordy.

    EDIT: No, I guess I'll stick with the binding. I thought I only had the three buttons doing any binding on the form, but overlooked two other parts that were also binding and would have had the same issue had I looked close enough. Those two fiddled with visibility rather than color, and one of them I had forgotten I had even added, though now that I see it...it was a good idea.

    In fact, much of the form could have been set up using binding, but some of it would have been so terribly painful that it wasn't worth it. I'm still learning where the balance is. I've only been using WPF for a couple months, by now. Everything that can be done via binding can be done without binding as well. I was doing too little with binding when I started, but have gone back and switched some of my early forms around so that they do more with binding. Not everything, though.

    I'm not sure what ends up being more readable, in the long run. Datatriggers are pretty nearly self documenting. They can be wordy, but tend to be quite explicit and clear.
    Last edited by Shaggy Hiker; Mar 30th, 2023 at 03:47 PM.
    My usual boring signature: Nothing

  5. #5
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,703

    Re: [RESOLVED] WPF Binding Issue

    What you have to understand about data binding is that it exists to facilitate a clean separation of the UI logic from "business" logic. It helps support patterns like MVVM and MVC. If you're all about separating your UI logic from everything else, then data binding is something you're going to want to get deep into. Otherwise, you can get by without it.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  6. #6

    Thread Starter
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    39,376

    Re: [RESOLVED] WPF Binding Issue

    There's also an intermediate position. I'm not full on MVVM. I have almost complete separation between UI and backend, but the front end does to a bit of fiddling about with UI. Some forms are pretty much 100% binding, some are not. This particular form is less binding than they otherwise would be.
    My usual boring signature: Nothing

  7. #7
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,703

    Re: [RESOLVED] WPF Binding Issue

    Quote Originally Posted by Shaggy Hiker View Post
    There's also an intermediate position. I'm not full on MVVM. I have almost complete separation between UI and backend, but the front end does to a bit of fiddling about with UI. Some forms are pretty much 100% binding, some are not. This particular form is less binding than they otherwise would be.
    Yea, I'm sort of like this as well. I'm in-between mixing and separating concerns.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width