2

I have what I'm sure is a ridiculously ignorant question, but I'm asking it anyways because I've searched and searched and either don't understand the solutions I'm seeing or not finding exactly the answer I seek.

I have an MVVM application. My XAML is setup with the DataContext set to the VM where the data items on the screen are populated from the VM's properties. My CodeBehind doesn't fiddle with the data, only things relating to the screen.

What I want to do now is bind certain UI elements to properties in the foo.xaml.cs (CodeBehind) file. For example, I want to specify FontSize's bound to properties in the CB so that in the WindowInitialized handler in the CB, it can detect screen sizes and change one variable to which all the screen items' FontSize= are bound.

I can solve this the wrong way by creating a public property in my VM and then "inject" the value from the CB into the VM. I know that will work, but it's a roundabout way to get the behavior I want, it's not at all straightforward, and I feel confident it's the wrong way to proceed.

I searched around and have tried things like:

    FontSize="{Binding RelativeSource={RelativeSource Self},Path="MyFontSize"

(where "MyFontSize" is a public int property) and a variety of other examples I found, but none have worked.

So specifically, if my CodeBehind class is called NameChangeSetupMainWindow and that's where the "MyFontSize" property lives,

public partial class NameChangeSetupMainWindow : Window
{
    private int m_fontSize = 14;
    public int MyFontSize
    {
        get { return m_fontSize; }
        set
        {
            if (m_fontSize != value))
            {
                m_fontSize = (value > 0) ? value : 10;
            }
        }
    }
    ...
    ... rest of the class...
    ...
}

and the VM is called NameChangeSetupViewModel and that's where the "real" data lives and the DataContext points ala:

<Window.DataContext>
    <local:NameChangeSetupViewModel/>
</Window.DataContext>

what is the syntax in XAML to bind just those UI items (tooltips related to the UI, font sizes, etc) to variables in the CodeBehind instead of housing them in the VM?

Thanks in advance for any guidance you can supply.

McGarnagle
  • 101,349
  • 31
  • 229
  • 260
John
  • 342
  • 3
  • 10
  • `{RelativeSource Self}` will only work for the `Window`. Where did you apply this binding? Btw, you could also change the fontsize of UI elements directly in code behind, without using binding. – Federico Berasategui Nov 22 '13 at 22:32
  • Yes, thanks, HighCore, I am considering that, but I thought it would be worthwhile to point a number of UI-specific things, such as FontSize and styles and such, to a centralized variable. – John Nov 22 '13 at 22:37
  • Oh, and for the "Where did you apply this binding?" I tried it in the XAML file inside of the " – John Nov 22 '13 at 22:46

1 Answers1

3

You can use RelativeSource AncestorType to bind to properties of the view itself:

<TextBlock FontSize="{Binding RelativeSource={RelativeSource AncestorType=Window},Path=MyFontSize}" />

Using ElementName should work as well:

<Window x:Name="window">

    <TextBlock FontSize="{Binding ElementName=window,Path=MyFontSize}" />
</Window>

Edit

Here is an example that I've confirmed working:

XAML

<Window x:Class="WpfAbc.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525"
    ToolTip="{Binding RelativeSource={RelativeSource Self},Path=MyToolTip}"
    >
    <Grid>
        <TextBlock Text="hello world" FontSize="{Binding RelativeSource={RelativeSource AncestorType=Window},Path=MyFontSize}" />
    </Grid>
</Window>

Code Behind

public partial class MainWindow : Window
{
    private int m_fontSize = 20;
    public int MyFontSize
    {
        get { return m_fontSize; }
        set
        {
            if (m_fontSize != value)
            {
                m_fontSize = (value > 0) ? value : 10;
            }
        }
    }

    public string MyToolTip
    {
        get { return "hello world"; }
    }

    public MainWindow()
    {
        InitializeComponent();
    }
}

Articles on this topic:

Related background:

Community
  • 1
  • 1
McGarnagle
  • 101,349
  • 31
  • 229
  • 260
  • I tried this verbatim, but it didn't work. I'll try again by changing "window" to "NameChangeSetupMainWindow" because I suspect that's what you meant in shortcut form (I'm still pretty neophyte on the syntax/semantics of binding) – John Nov 22 '13 at 22:39
  • Well, maybe not...that generated an error of: "member names cannot be the same as their enclosing type" with the line number of this statement: x:Name="NameChangeSetupMainWindow" – John Nov 22 '13 at 22:40
  • I tried both of the above examples, but neither worked. Rather than the FontSize, I tried setting the "ToolTip" in the Window as in the following where ToolTip is a public string property in the CB file, but no go: ` – John Nov 22 '13 at 22:42
  • @John hm, is the binding inside an outside-the-visual-tree element (popup, context menu), or inside a data template? That's the only reason I can think of, why the above would not work. – McGarnagle Nov 22 '13 at 22:46
  • It's inside the tag. I'm trying it with the ToolTip for the main window: ToolTip="{Binding RelativeSource={RelativeSource AncestorType=Window},Path=ToolTip}" -- the "ToolTip" property is a public string inside of the NameChangeSetupMainWindow:Window (the foo.xaml.cs file). – John Nov 22 '13 at 22:49
  • UPDATE: I had to rename "ToolTip" to "MyToolTip" due to a warning. The property in the *.xaml.cs file is now public string MyToolTip and the XAML code is: ToolTip="{Binding RelativeSource={RelativeSource AncestorType=Window},Path=MyToolTip}" – John Nov 22 '13 at 22:52
  • @John if it's on the Window itself, then you'll need `RelativeSource Self`... but wait, could it be the problem is just that you're not calling `RaisePropertyChanged` for the Font Size? – McGarnagle Nov 22 '13 at 22:55
  • Not sure -- right now I'm trying it on the ToolTip of the main window. For grits and shins, I put a 'NotifyPropertyChanged("MyToolTip")' in the VM just to see if that would get the tooltip to show up when I mouse over the window, but it doesn't. If I just put text into the ="Hello World!" of the ToolTip it shows up, but the binding acts as if there's no tooltip – John Nov 22 '13 at 22:58
  • @John that's weird. Please see my edit above, a simplified example that works ... – McGarnagle Nov 22 '13 at 23:05
  • That works! Thank you so much! Do you have a link to a good tutorial on binding, and/or a good reference page? I'm delighted beyond words this is working, thanks to you, but a solution without a fundamental understanding of why it worked stops short of my objective. Is it "Relative Self" because the XAML is essentially the same class as the CB, and thus "Self" is like a "this" reference? I'm still fuzzy to this versus when to use "RelativeSource={Relative Source AncestorType=Window}..." etc...I really want to make sure I understand the construct. In any event, thanks again! – John Nov 23 '13 at 21:42
  • @John yes, "Relative Self" is because XAML/CB is literally the same class (this is implemented "behind the scenes" using C# partial classes). As far as articles, I've always found MSDN to be good and thorough (and well organized, so it's easy to browse different topics). I added a few articles above that I found informative. Also, one crucial trick for debugging WPF bindings: watch the Output window in Visual Studio. If a binding fails, you will often see a helpful error message there. – McGarnagle Nov 23 '13 at 22:21
  • 2
    Thank you -- I will re-peruse MSDN + the links you provided. For those new to MVVM who might encounter my question and the answers above, binding the variables in the CB file did require that I add interface **INotifyPropertyChanged** and implement the necessary plumbing to fire the **NotifyPropertyChanged("MyToolTip")** events. While this is fundamental, if you're reading this question it's possible you might not know that. I'll leave the messy details out, but the signature now looks like this: `public partial class NameChangeSetupMainWindow : Window, INotifyPropertyChanged` – John Nov 23 '13 at 23:25