Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/277.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么不是';这个Silverlight附属酒店不工作吗?_C#_Data Binding_Silverlight 3.0_Mvvm_Delegates - Fatal编程技术网

C# 为什么不是';这个Silverlight附属酒店不工作吗?

C# 为什么不是';这个Silverlight附属酒店不工作吗?,c#,data-binding,silverlight-3.0,mvvm,delegates,C#,Data Binding,Silverlight 3.0,Mvvm,Delegates,我试图在Silverlight 3应用程序中使用MVVM模式,但在绑定到视图模型的命令属性时遇到问题。首先,我尝试添加一个名为ClickCommand的附加属性,如下所示: public static class Command { public static readonly DependencyProperty ClickCommandProperty = DependencyProperty.RegisterAttached( "Click

我试图在Silverlight 3应用程序中使用MVVM模式,但在绑定到视图模型的命令属性时遇到问题。首先,我尝试添加一个名为ClickCommand的附加属性,如下所示:

public static class Command
{
    public static readonly DependencyProperty ClickCommandProperty = 
        DependencyProperty.RegisterAttached(
            "ClickCommand", typeof(Command<RoutedEventHandler>), 
            typeof(Command), null);

    public static Command<RoutedEventHandler> GetClickCommand(
        DependencyObject target)
    {
        return target.GetValue(ClickCommandProperty) 
            as Command<RoutedEventHandler>;
    }

    public static void SetClickCommand(
        DependencyObject target, Command<RoutedEventHandler> value)
    {
        // Breakpoints here are never reached
        var btn = target as ButtonBase;
        if (btn != null)
        {
            var oldValue = GetClickCommand(target);
            btn.Click -= oldValue.Action;

            target.SetValue(ClickCommandProperty, value);
            btn.Click += value.Action;
        }
    }
}
公共静态类命令
{
公共静态只读从属属性ClickCommandProperty=
DependencyProperty.RegisterAttached(
“点击命令”,类型(命令),
typeof(命令),空);
公共静态命令GetClickCommand(
依赖对象(目标)
{
返回target.GetValue(ClickCommandProperty)
作为指挥;
}
公共静态void SetClickCommand(
DependencyObject(目标,命令值)
{
//这里的断点永远不会到达
var btn=作为按钮库的目标;
如果(btn!=null)
{
var oldValue=GetClickCommand(目标);
点击-=oldValue.Action;
target.SetValue(单击CommandProperty,value);
btn.Click+=value.Action;
}
}
}
泛型命令类是围绕委托的包装器。我之所以包装一个委托,是因为我想知道属性的委托类型是否是事情最初不适合我的原因。这是一节课:

public class Command<T> /* I'm not allowed to constrain T to a delegate type */
{
    public Command(T action)
    {
        this.Action = action;
    }

    public T Action { get; set; }
}
public class Command/*我不允许将T约束为委托类型*/
{
公共命令(T行动)
{
这个。行动=行动;
}
公共T操作{get;set;}
}
以下是我如何使用附加属性:

<Button u:Command.ClickCommand="{Binding DoThatThing}" Content="New"/>

语法似乎被接受了,我认为当我用字符串属性类型测试所有这些时,效果很好。以下是要绑定到的视图模型类:

public class MyViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged = delegate { };

    public Command<RoutedEventHandler> DoThatThing
    {
        get
        {
            return new Command<RoutedEventHandler>(
                (s, e) => Debug.WriteLine("Never output!"));
        }
    }
}
公共类MyViewModel:INotifyPropertyChanged
{
公共事件PropertyChangedEventHandler PropertyChanged=委托{};
公共命令
{
得到
{
返回新命令(
(s,e)=>Debug.WriteLine(“从不输出!”);
}
}
}
从不调用Command属性中包含的委托。此外,当我在附加属性的getter和setter中放置断点时,它们永远不会到达

在试图隔离问题时,我将属性类型更改为string;getter和setter中的断点也从未到达,但是在它们中抛出异常确实会导致应用程序终止,所以我认为这是框架的异常


为什么这些东西不起作用?我还欢迎其他更简单的方法来绑定事件处理程序以查看模型。

这里至少有两个问题

首先,您依赖于正在执行的SetXxx方法。当从XAML设置DP时,不执行依赖属性(属性设置器或SetXxx方法)的CLR包装器;相反,WPF直接设置内部管理的DP“slot”的值。(这也解释了为什么断点从未命中。)因此,处理更改的逻辑必须始终出现在OnXxxChanged回调中,而不是setter中;当属性更改时,无论更改来自何处,WPF都将为您调用该回调。因此(示例取自一个稍有不同的命令实现,但应该能让您了解这一点):


其次,即使进行了此更改,在尚未设置值的控件上设置ClickCommand也会导致异常,因为oldValue为null,因此oldValue.Action会导致NullReferenceException。您需要检查这种情况(您还应该检查newValue==null,尽管这种情况不太可能发生)。

。你试过使用非通用版本吗?好主意。但是,我刚刚尝试创建了一个
RoutedEventCommand
类,并用它替换了
命令的实例,其行为是相同的。非常感谢。执行更改的处理程序解决了问题。@itowlson,这是一个很好的解释。让我明白了一些事情,这让我头疼。谢谢
// Note callback in PropertyMetadata

public static readonly DependencyProperty CommandProperty =
  DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(Click),
  new PropertyMetadata(OnCommandChanged));

// GetXxx and SetXxx wrappers contain boilerplate only

public static ICommand GetCommand(DependencyObject obj)
{
  return (ICommand)obj.GetValue(CommandProperty);
}

public static void SetCommand(DependencyObject obj, ICommand value)
{
  obj.SetValue(CommandProperty, value);
}

// WPF will call the following when the property is set, even when it's set in XAML

private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
  ButtonBase button = d as ButtonBase;
  if (button != null)
  {
    // do something with button.Click here
  }
}