Metro: Why is binding from XAML to a property defined in code-behind not working?

一笑奈何 提交于 2020-01-07 04:26:08

问题


I am attempting to adapt a Windows Metro-style app sample slightly by binding the title text to a property defined in code-behind, but I can't seem to get it to work. Reading the blog post titled Bind from XAML to property defined in code-behind, I am trying out "Solution 1".

Here is my XAML source (simplified):

<UserControl x:Class="... .MainPage" x:Name="UserControlSelf"
    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"
    mc:Ignorable="d"
    d:DesignHeight="768" d:DesignWidth="1366">

    <Grid x:Name="LayoutRoot" Style="{StaticResource LayoutRootGridStyle}">
        <Grid.RowDefinitions>
            <RowDefinition Height="140"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <Grid x:Name="TitlePanel">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>

            <Button x:Name="BackButton" Click="BackButton_Click" Style="{StaticResource BackButtonStyle}"/>
            <TextBlock x:Name="PageTitle" Text="{Binding ElementName=UserControlSelf, Path=Title}" Style="{StaticResource TitleStyle}" Grid.Column="1"/>
        </Grid>
    </Grid>
</UserControl>

And here is my code-behind (simplified):

public partial class MainPage
{
    private string _title;

    public MainPage()
    {
        _title = "Test";
        InitializeComponent();
    }

    public string Title
    {
        get
        {
            return _title;
        }
    }

    //...
}

I set a breakpoint on the line return _title; in the getter of the Title property. When I debug the app, I see the back button, but the title text block control is blank (no text) and the breakpoint is not triggered:

I set a breakpoint in the autogenerated C# code for the XAML file and verified that UserControlSelf is identical to this within InitializeComponent().

How do I bind the Text of the title text block control to the Title property defined in code-behind?


回答1:


Can't test Metro app right now, but maybe you should implement INotifyPropertyChanged so the binding can work.

In your code behind:

public event PropertyChangedEventHandler PropertyChanged;

private void NotifyPropertyChanged(string info)
{
    if (PropertyChanged != null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(info));
    }
}

public string Title
{
    get
    {
        return this._title;
    }

    set
    {
        if (this._title != value)
        {
            this._title = value;
            NotifyPropertyChanged("Title");
        }
    }
}

Also change

 _title = "Test";

to

 this.Title = "Test";



回答2:


I was finally able to get it working. Instead of messing around with ElementName and Path, I simply set the MainPage instance's DataContext to an object other than the MainPage instance that had a Title property. I then changed the Text attribute of the title text block to {Binding Title}.

It does not appear to be necessary for the data context object to implement Windows.UI.Xaml.Data.INotifyPropertyChanged; however, by doing so, the binding automatically behaves like a "one way" binding.

I originally tried setting this.DataContext = this;, but, as I found out, that does not work. If I set it to a POCO or view model instance, then the binding is established.

It would be interesting to know why this.DataContext = this; is erroneous, but at least I can now proceed.




回答3:


I've not used Metro, but in WPF, that won't work because Title needs to be a Dependency Property. Change your code behind like this:

public partial class MainPage
{


    public static readonly DependencyProperty TitleProperty;
    public string Title
    {
        get { return (string)GetValue(TitleProperty); }
        set { SetValue(TitleProperty, value); }
    }

    static MainPage()
    {
        TitleProperty= DependencyProperty.Register(
            "Title",
            typeof(string),
            typeof(MainPage));
    }

    public MainPage()
    {
        InitializeComponent();
        Title = "Test";
    }
}

This caught me out yesterday, it's so easy to forget to do.




回答4:


This technique always works for me

Text="{Binding ElementName=LayoutRoot, Path=Parent.Title}"

This assumes that the user control’s child element name is “LayoutRoot” which it is by default.



来源:https://stackoverflow.com/questions/8636713/metro-why-is-binding-from-xaml-to-a-property-defined-in-code-behind-not-working

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!