【问题标题】:Access function of C# from XAML从 XAML 访问 C# 的函数
【发布时间】:2015-02-13 18:39:33
【问题描述】:

我的 XAML 代码中有这个按钮-

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

我还有另一个 C# 代码-

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
         }
    }
  }

我的问题是如何在我的xaml 代码中获取Button 的Content 以存储来自C# 代码函数的值?

【问题讨论】:

    标签: c# xaml visual-studio-2012 visual-studio-2013


    【解决方案1】:

    你通过绑定来完成这个。绑定有几个规则:

    • 您只能绑定到属性
    • 这些属性必须是公开的
    • 对于要评估的绑定,属性必须位于视图的DataContext

    该数据上下文通常是 ViewModel 对象,而不是视图本身,遵循 MVVM 模式。

    因此,在您的视图模型中,您将拥有:

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

    那么一旦你设置了数据上下文,你的 XAML 就是:

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

    【讨论】:

    • 请注意,有一些方法可以通过设置 Source 或 RelativeSource 来绕过 DataContext 限制 - 这些提供了通过静态值或 DataContext 的其他控件进行绑定的能力跨度>
    • 还可以使用RelativeSource 将按钮的数据上下文设置为父MainPage 类。然后您可以绑定到“代码背后”中的属性,但我强烈建议您使用视图模型并遵循 MVVM 架构。 (见stackoverflow.com/questions/84278/…)
    • @BradleyDotNET 我尝试了上面的实现。但它给了我这个错误-An exception of type 'System.NullReferenceException' occurred in MyGame.exe but was not handled in user code
    • @Coder 捕获异常并进行一些调试。这些信息不足以让我提供帮助,无论如何您都需要能够调试您的 NRE :)
    • @BradleyDotNET 对不起,但我仍然无法弄清楚。我已经用错误编辑了上面的代码。而且按钮的内容没有显示任何内容。
    【解决方案2】:

    由于您没有提到同步的必要性,因此对您的问题最简单的回答是使用 x:Name 标识符并在 C# 代码中的函数中设置 content 属性。

    button.Content = name();
    

    如果您可以将您的方法移动到不同的类中,您还可以使用 ObjectDataProvider 将您的方法 name 连接到 XAML 代码,然后使用数据绑定将数据提供程序连接到您的代码:

    <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>
    

    但是,如果您想要一种更简单的方法,并且希望您的数据与 UI 同步(因此,每当您更改数据中的某些内容时,它都会自动反映在 UI 控件上)您可以将您的函数转换为readonly 属性 并按照@BradleyDotNET 的建议进行操作。

    一般来说,将数据绑定与实际数据分开,被认为是一件好事。

    请注意,在 WPF 中,您始终可以在 XAML 中以声明方式执行操作,但您也可以使用 C# 在代码中以编程方式执行相同操作。大多数人更喜欢声明式的方式,但很高兴知道如果需要,您可以在 C# 中做同样的事情(甚至更多)。

    请使用.NET framework naming conventions,并使用pascalCase 命名您的方法。

    【讨论】:

      【解决方案3】:

      如果您想从 XAML 访问方法,您的选择相对有限。

      第一个也是最明显的是使用事件处理程序,它进入你的View 的代码隐藏,因此违反了 MVVM。但是,可以提供执行代码的最简单方法。如果您使用的是ViewModel,您还可以使用dynamic 对所需方法执行后期绑定 - 但只能从 C# 代码。

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

      在代码隐藏中

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

      请注意,虽然可以使用特定类型的 ViewModel 而不是 dynamic,但这也违反了 MVVM 模式 - 并且比后面的代码更糟糕,因为它会强制你的 View与特定的ViewModel 一起使用。

      另一种选择是使用 Interactions 和 CallMethodAction(来自 Expressions Blend SDK)。

      <Button>
          <i:Interaction.Triggers>
              <i:EventTrigger EventName="Click">
                  <ei:CallMethodAction MethodName="ButtonClicked"/>
              </i:EventTrigger>
          </i:InterAction.Triggers>
      </Button>
      

      【讨论】:

      • 我认为所有视图都是为了与特定的视图模型一起工作。随意通过接口解耦,但要说dynamic是一个很好的解决方案,更别说唯一了,有点牵强
      猜你喜欢
      • 2012-03-19
      • 1970-01-01
      • 1970-01-01
      • 2011-11-23
      • 2011-01-03
      • 2023-01-17
      • 1970-01-01
      • 2013-10-06
      相关资源
      最近更新 更多