Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/266.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# WPF如何注销附加的行为_C#_Wpf_Xaml_Mvvm - Fatal编程技术网

C# WPF如何注销附加的行为

C# WPF如何注销附加的行为,c#,wpf,xaml,mvvm,C#,Wpf,Xaml,Mvvm,我正在用WPF写一份申请书。我有一个类似于Sheridan在中描述的设置 具体地说,我有一个listview,它有一个select命令,将我的RootViewModel上的Mainview属性设置为所选条目的属性。它显示在以下XAML中 <DockPanel> <UserControl DockPanel.Dock="Top" Content="{Binding MenuView,Mode=OneWay}"/> <Border DockPanel.D

我正在用WPF写一份申请书。我有一个类似于Sheridan在中描述的设置

具体地说,我有一个listview,它有一个select命令,将我的RootViewModel上的Mainview属性设置为所选条目的属性。它显示在以下XAML中

<DockPanel>
    <UserControl DockPanel.Dock="Top" Content="{Binding MenuView,Mode=OneWay}"/>
    <Border DockPanel.Dock="Top" BorderThickness="0 2 0 0" BorderBrush="{StaticResource GarminDarkBrush}"  Panel.ZIndex="1001">
        <DockPanel LastChildFill="True">
            <UserControl DockPanel.Dock="Left" Content="{Binding ExpandableLeftPanel,Mode=OneWay}"   />
            <UserControl Content="{Binding MainView,Mode=OneWay}"   Panel.ZIndex="0" />
        </DockPanel>
    </Border>
</DockPanel>
这适用于显示不同的条目

现在来谈谈我的问题。在我显示的每个viewmodels中,都有一个子CONSOLUECOWERVIEWMODEL,该子CONSOLUECOWERVIEWMODEL具有一个CONSOLUEVIEWMODEL,在显示时将附加的行为注册到RichTextBox。当我选择列表中的每个项目时,将显示正确的视图,并且ConsoleViewModel将正确注册和运行。但是,当我在视图之间切换时,行为永远不会取消注册。这会导致一个问题,因为每当我切换视图时,都会创建一个新的RichTextBox(由WPF而不是我创建)并绑定到我的行为。这通常会导致内存泄漏,因为我将事件处理程序附加到RTB。我通过使用ConsoleViewModel字典并通过ConsoleMediator类交换与ConsoleViewModel关联的RTB修复了此内存泄漏

我仍然希望了解如何正确地注销RTB,以便在视图之间交换时,可以注销ConsoleViewModel上的其他事件处理程序,这会浪费CPU更改未显示的RTB,并且无论如何查看时都会被替换

ConsoleControlServiceWModel的一部分

public class ConsoleControllerViewModel : ViewModelBase
{
    public virtual ConsoleViewModel Console { get; set; }
}
下面是附加的行为

public static class ConsoleTextBoxBehavior
{
    public static readonly DependencyProperty ConsoleBindingProperty =
                   DependencyProperty.RegisterAttached("Console",
                   typeof(ConsoleViewModel), typeof(ConsoleTextBoxBehavior),
                   new UIPropertyMetadata(null, OnConsoleBound));

    public static ConsoleViewModel GetConsole(DependencyObject obj)
    {
        return (ConsoleViewModel)obj.GetValue(ConsoleBindingProperty);
    }

    public static void SetConsole(DependencyObject obj, ConsoleViewModel value)
    {
        obj.SetValue(ConsoleBindingProperty, value);
    }

    private readonly static Dictionary<ConsoleViewModel, ConsoleMediator> _registeredConsoles =
        new Dictionary<ConsoleViewModel, ConsoleMediator>();

    private static void OnConsoleBound(object sender, DependencyPropertyChangedEventArgs e)
    {
        var textBox = sender as RichTextBox;
        if(textBox == null)
        {
            throw new ArgumentException("Can only bind to RichTextBoxes");
        }
        var c = e.OldValue as ConsoleViewModel;
        if (e.OldValue != null && _registeredConsoles.ContainsKey(c))
        {
            // never hit
            var cm = _registeredConsoles[c];
            cm.UnhookConsole();
            _registeredConsoles.Remove(c);
        }
        c = e.NewValue as ConsoleViewModel;
        if (c != null)
        {
            HookUpConsole(textBox, c);
        }
    }

    //other functions left out for brevity
}
公共静态类ConsoleTextBoxBehavior
{
公共静态只读从属属性ConsoleBindingProperty=
DependencyProperty.RegisterAttached(“控制台”,
typeof(控制台视图模型)、typeof(控制台ExtBoxBehavior),
新的UIPropertyMetadata(null,OnConsolleBound));
公共静态控制台ViewModel GetConsole(DependencyObject obj)
{
return(ConsoleViewModel)对象GetValue(ConsoleBindingProperty);
}
公共静态void SetConsole(DependencyObject对象、ConsoleViewModel值)
{
对象设置值(ConsoleBinding属性,值);
}
专用只读静态字典\u注册的解决方案=
新字典();
ConsolleBound上的私有静态无效(对象发送方,DependencyPropertyChangedEventArgs e)
{
var textBox=发送方为RichTextBox;
if(textBox==null)
{
抛出新ArgumentException(“只能绑定到RichTextBox”);
}
var c=e.OldValue作为控制台视图模型;
if(e.OldValue!=null&&u registeredConsoles.ContainsKey(c))
{
//从不打
var cm=_注册的解决方案[c];
cm.UnhookConsole();
_已注册的解决方案。删除(c);
}
c=e.作为控制台视图模型的新值;
如果(c!=null)
{
连接控制台(文本框,c);
}
}
//为简洁起见,省略了其他函数
}
这里它被连接到RTB。请注意,{Binding.}之所以有效,是因为它来自于ConsoleView模型的上下文,而不是ConsoleController服务模型

<RichTextBox Name="ConsoleOutput"
             ext:ConsoleTextBoxBehavior.Console="{Binding .}"
             IsReadOnly="True"
             >

我理解,当通知特定属性发生更改时,应调用OnConsoleBound。在我的特定应用程序中,我从不需要该ConsoleView模型相对于其父级进行更改。那么,我是否必须修改viewmodel以侦听rootview上的事件,以确定它是否是实际显示的事件?然后将Viewmodel切换到临时位置,然后在显示时将其放回原位?看起来很难看,所以我想在弄得一团糟之前向花生画廊寻求另一个解决方案

此外,ViewModelBase是一个INotifyPropertyChanged,我有一些魔术(动态代理)来为虚拟成员引发这些事件。因此,请不要因为没有看到正在引发的属性更改事件而挂断电话

<RichTextBox Name="ConsoleOutput"
             ext:ConsoleTextBoxBehavior.Console="{Binding .}"
             IsReadOnly="True"
             >