My task is to implement a MDI-like interface in our WPF app.
I have created this simple class as a base for all the views:
public class BaseView : UserControl, INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string? name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
private ViewType _type = ViewType.Null;
private string _tabTitle = string.Empty;
private bool _isSelected = false;
public ViewType Type { get => _type; set { _type = value; OnPropertyChanged(); } }
public string TabTitle { get => _tabTitle; set { _tabTitle = value; OnPropertyChanged(); } }
public bool IsSelected { get => _isSelected; set { _isSelected = value; OnPropertyChanged(); } }
}
Next, I created few test Views. All of them start like this: <local:BaseView...
In main window, there are two controls: ItemsControl (for displaying the list of opened views), and ContentControl (for displaying the selected view.)
I store all the opened views in a ObservableCollection: ObservableCollection<BaseView>...
. I wanted to display them as a list, so I created ItemsControl:
<ItemsControl x:Name="mainItemsControl">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Padding="2" Margin="2" Tag="{Binding Type}">
<TextBlock Text="{Binding TabTitle}" Foreground="White"/>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
When I set the ItemsControl's source ( mainItemsControl.ItemsSource = openedViews;
) and started the application, ItemsControl displayed the content of each View instead of the ItemTemplate (Border with the TextBlock). What did I do wrong?
If I understood correctly, then the openedViews collection consists of BaseView. If so, then BaseView is a UIElement.
But Data Templates are used to render non UIElements.
If the Content receives a UIElement, then it is rendered directly as is.
One possible variant solution.
You need to remove the INotifyPropertyChanged interface from BaseView. Create a data source for your BaseView with an implementation of INotifyPropertyChanged.
In BaseView create DependencyProperty for this source.
Create a simple, helper container for the openedViews collection.
Something like this (pseudo code):
public class SomeContainer
{
public BaseDataSource DataSource
{
get => _dataSource;
set
{
_dataSource = null;
if(View is not null)
{
View.DataSource = DataSource;
}
}
}
public BaseView View
{
get => _view;
set
{
_view = value;
if(_view is not null)
{
_view.DataSource = DataSource;
}
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.