首先,这是使用 MVVM 的向导控件的简化版本。该问题更容易重现,如下所述

经过大量缩小范围后,我解决了代码中由 WPF ContentControl 引起的无限异常。但是,我还没有弄清楚如何处理它,除了 try-catch 包装我所有可能的实例化代码。这是重现此内容的示例代码...任何有关如何防止发生这种无限异常的帮助将不胜感激。

其他详细信息

总结一下,问题是如果内容控件改变了它的内容,并且正在加载的东西抛出异常,那么它就会抛出,然后重试加载,导致一次又一次的抛出。

MainWindow.xaml

<Window x:Class="WpfApplication8.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" Name ="Main">
    <Grid>

        <ContentControl Name="bar" Content="{Binding ElementName=Main, Path=foo}"/>
    <Button Click="ButtonBase_OnClick" Margin="20" Width="50"/>
  </Grid>
</Window>

MainWindow.xaml.cs
public partial class MainWindow : Window, INotifyPropertyChanged
{
    private UserControl _foo;
    public UserControl foo
    {
        get { return _foo; }
        set { _foo = value; OnPropertyChanged("foo"); }
    }

    public MainWindow()
    {
        InitializeComponent();
        foo = new UserControl1();
    }

    private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
    {
        foo = new UserControl2();
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

UserControl1 为空,所有默认值

UserControl2.xaml.cs
public UserControl2()
{

  InitializeComponent();
  throw new Exception();
}

最佳答案

不要将 ContentControl 绑定(bind)到 MainWindow。而是使用 DataTemplates 来选择 MainWindow 的内容。一种设计示例的方法是将 ContentControl 的 Content 绑定(bind)到 MainWindow 的 DataContext。

首先需要一些可观察的测试数据。这些数据的细节并不重要。要点是有两种不同类别的测试数据可供选择 - TestData.cs :

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;

namespace fwWpfDataTemplate
{
    // Classes to fill TestData
    public abstract class Person : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
        string _name;
        public string Name
        {
            get { return _name; }
            set
            {
                _name = value;
                OnPropertyChanged("Name");
            }
        }
    }
    public class Student : Person { }
    public class Employee : Person
    {
        float _salary;
        public float Salary
        {
            get { return _salary; }
            set
            {
                _salary = value;
                OnPropertyChanged("Salary");
            }
        }
    }

    public class TestData : ObservableCollection<Person>
    {
        public TestData()
            : base(new List<Person>()
            {
                new Student { Name = "Arnold" },
                new Employee { Name = "Don", Salary = 100000.0f }
            }) { }
    }
}

然后将 DataTemplates 添加到 MainWindow 的资源 - MainWindow.xaml :
<Window x:Class="fwWpfDataTemplate.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:me="clr-namespace:fwWpfDataTemplate"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <DataTemplate DataType="{x:Type me:Student}">
            <StackPanel>
                <TextBlock Text="Student"/>
                <TextBlock Text="{Binding Name}"/>
            </StackPanel>
        </DataTemplate>
        <DataTemplate DataType="{x:Type me:Employee}">
            <StackPanel>
                <TextBlock Text="Employee"/>
                <TextBlock Text="{Binding Name}"/>
                <TextBlock Text="Salary"/>
                <TextBlock Text="{Binding Salary}"/>
            </StackPanel>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Button Content="Change Data Context" Click="Button_Click" />
        <ContentControl Grid.Row="1" Content="{Binding}"/>
    </Grid>
</Window>

注意:DataTemplates 的内容可以是 UserControl1、UserControl2 等,而不是 StackPanels。

然后添加一些代码来更改数据上下文 - MainWindow.cs :
using System.Windows;

namespace fwWpfDataTemplate
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        TestData testData = new TestData();
        int testIndex = -1;
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            testIndex = (testIndex + 1) % testData.Count;
            this.DataContext = testData[testIndex];
        }
    }
}

享受。

关于c# - 内容控件中无限发生的异常,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23345321/

10-12 17:51
查看更多