内容控制中无限发生异常

时间:2014-04-28 15:38:50

标签: c# .net wpf xaml

首先,这是使用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();
}

1 个答案:

答案 0 :(得分:0)

不要将ContentControl绑定到MainWindow。而是使用DataTemplates选择MainWindow的内容。一个示例设计的方法是将ContentControl的内容绑定到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];
        }
    }
}

享受。