1

I have this button in my XAML code-

           <Button x:Name="button" 
            Content="{Binding Name}" 
            Click="Start"  
            HorizontalAlignment="Left" 
            Margin="123,45,0,0" 
            VerticalAlignment="Top"/>

I have another C# code-

namespace MyGame
{

    public sealed partial class MainPage : Page
    {
        public string Name()
          {

             get{ return "Hello" };
          }
       private void ButtonNo3(object sender, RoutedEventArgs e)
        {

          Button obj = (Button)sender;

          var selectedButton = obj.Content.ToString();
          //This is where I get this error-An exception of type        'System.NullReferenceException' occurred in MyGame.exe but was not handled in user code
         }
    }
  }

My question is how can I get Content of my Button in my xaml code to store the value from the function of C# code?

3 Answers3

2

You accomplish this via binding. Binding has a couple rules:

  • You can only bind to properties
  • Those properties must be public
  • For the binding to evaluate, the property must be on the View's DataContext

That data context is usually a ViewModel object instead of the view itself, following the MVVM pattern.

So in your view model, you would have:

//Properties (and methods) are PascalCase!
public string Name { get { return "Hello";} }

Then once you set the data context, your XAML is:

      <Button x:Name="button" 
        Content="{Binding Name}" 
        Click="Start"  
        HorizontalAlignment="Left" 
        Margin="123,45,0,0" 
        VerticalAlignment="Top"/>
BradleyDotNET
  • 60,462
  • 10
  • 96
  • 117
  • Note that there are ways to duck around the `DataContext` restriction by setting the `Source` or `RelativeSource` - these offer the ability to bind through static values or `DataContext` of other controls – David Feb 13 '15 at 18:49
  • It is also possible to set the button's data context to the parent MainPage class using a RelativeSource. Then you could bind to properties in the "code behind" but I would strongly recommend going with a View Model and following the MVVM architecture. (See http://stackoverflow.com/questions/84278/how-do-i-use-wpf-bindings-with-relativesource) – dbudzins Feb 13 '15 at 18:49
  • @BradleyDotNET I tried the above implementation.But it is giving me this error- `An exception of type 'System.NullReferenceException' occurred in MyGame.exe but was not handled in user code` –  Feb 13 '15 at 18:54
  • @Coder Trap the exception and do some debugging. Thats not enough information for me to help, and you need to able to debug your NREs anyways :) – BradleyDotNET Feb 13 '15 at 18:57
  • @BradleyDotNET Sorry But I am still not able to figure it out.I have editted my code above with the error.Also the contents of the Button is not displaying anything. –  Feb 13 '15 at 19:41
  • @Coder You still need to set the `DataContext`. If you insist on doing so in the code-behind, write `this.DataContext = this` in the constructor (note, this is *terrible* design). – BradleyDotNET Feb 13 '15 at 19:53
1

Since you haven't mentioned the need for syncing, the simplest answer to your question would be to use the x:Name identifier and just set the content property from a function in your C# code.

button.Content = name();

In case your can move your method into a different class, you can also use an ObjectDataProvider to wire up your method name to the XAML code, and then use data-binding to connect the data provider to your code:

<Grid>
    <Grid.Resources>
        <ObjectDataProvider x:Key="fnName"
                         ObjectType="{x:Type bind:SomeClassHoldingYourMethod}"
                         MethodName="name">
        </ObjectDataProvider>
    </Grid.Resources>
    <Button x:Name="button" 
        Content="{Binding Source={StaticResource fnName}, Mode=OneTime}" 
        HorizontalAlignment="Left" 
        Margin="123,45,0,0" 
        VerticalAlignment="Top"/>
</Grid>

However if you want a simpler approach and you want your data to be in sync with the UI (so whenever you change something in your data it is reflected on the UI controls automatically) you can convert your function to a readonly property and do what @BradleyDotNET suggested.

In general, separating data-binding from actual data, is considered a good thing.

Be aware that in WPF you can always do stuff declaratively in XAML, but you can also do the same thing in code programmatically using C#. Most people prefer the declarative way, but it's good to know you can do the same (and more) in C# if you need it.

And please, use the .NET framework naming conventions, and name your methods with pascalCase.

Faris Zacina
  • 14,056
  • 7
  • 62
  • 75
0

If you want to access methods from XAML, your options are relatively restricted.

The first and most obvious is to use event handlers, which go into the code-behind of your View and thus violate MVVM. The can, however, offer the easiest way to execute code. If you are using a ViewModel, you can also use dynamic to perform late binding to the desired method - but only from C# code.

<Button ...
        Clicked="Button_OnClick"/>

and in code-behind

public void Button_OnClick(object sender, RoutedEventArgs e)
{
    (DataContext as dynamic).ButtonClicked;
}

Note that while it is possible to use the specific type of ViewModel instead of dynamic, this would also be a violation of MVVM pattern - and a far worse one than code behind, because it forces your View to be used with a particular ViewModel.

Another option is to utilize Interactions and a CallMethodAction (from the Expressions Blend SDK).

<Button>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Click">
            <ei:CallMethodAction MethodName="ButtonClicked"/>
        </i:EventTrigger>
    </i:InterAction.Triggers>
</Button>
David
  • 10,458
  • 1
  • 28
  • 40
  • I would contend that all views are made to work with a particular view model. Feel free to decouple via an interface, but to say that `dynamic` is a good solution, let alone the only one, is a bit of a stretch – BradleyDotNET Feb 13 '15 at 18:59