gpt4 book ai didi

c# TabControl 不会刷新

转载 作者:行者123 更新时间:2023-11-30 21:41:11 32 4
gpt4 key购买 nike

我正在用单个窗口中的 TabControl 编写 WPF 桌面应用程序。我在 XAML View 中对一些属性进行了数据绑定(bind),只要在 .cs 文件的构造函数中更改了值,它就可以正常工作。稍后所做的更改不会显示在 View 中。

我有 4 个文件(实际上做的事情):MainWindow.xaml(显示 TabControl + 一些按钮):

<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>

<Window.Resources>

<SystemGesture:Double x:Key="FontSize">14</SystemGesture:Double>
<SystemGesture:Double x:Key="ImageSize">26</SystemGesture:Double>
<SystemGesture:Double x:Key="MenuButtonSize">30</SystemGesture:Double>

<DataTemplate DataType="{x:Type local:ViewModelBooks}">
<local:ViewBooks/>
</DataTemplate>

<DataTemplate DataType="{x:Type local:ViewModelFiles}">
<local:ViewFiles/>
</DataTemplate>

<DataTemplate DataType="{x:Type local:ViewModelMusic}">
<local:ViewMusic />
</DataTemplate>

</Window.Resources>
<TabControl x:Name="TabControlMain" TabStripPlacement="Left"
ItemsSource="{Binding Screens}"
Background="{DynamicResource BackgroundLight}"
SelectedItem="{Binding SelectedItem}"
>

MainWindowViewModel.cs(选择要显示的屏幕并将菜单命令委托(delegate)给 ViewModelBooks 对象):

namespace Bla{
public class MainWindowViewModel {

public MainWindowViewModel() {

MenuCommand = new RelayCommand(o => {
Debug.WriteLine("Menu Command " + o);
SwitchBooks(o);
});

SelectedItem = "Bla.ViewModelBooks";
}

private object _selectedItem;
public object SelectedItem {
get {
return _selectedItem;
}
set {
_selectedItem = value;
}
}

object[] _screens = new object[] { new ViewModelBooks(), new ViewModelMusic() };

public object[] Screens {
get {
return _screens;
}
}

public ICommand MenuCommand {
get; set;
}

internal void SwitchBooks(object o) {

if (o.ToString().Equals("Bla.ViewModelBooks")) {
((ViewModelBooks)_screens[0]).SwitchView();
}
}
}

public class CommandViewModel {
private MainWindowViewModel _viewmodel;

public CommandViewModel(MainWindowViewModel viewmodel) {

_viewmodel = viewmodel;

MenuCommand = new RelayCommand(o => {
_viewmodel.SwitchBooks(o);
});
}

public ICommand MenuCommand {
get; set;
}
public string Title {
get;
private set;
}
}

public class RelayCommand ...

ViewBooks.xaml(包含书籍列表。还有这个 TextBlock):

    <UserControl x:Class="Bla.ViewBooks"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Bla"
mc:Ignorable="d"
d:DesignHeight="900" d:DesignWidth="900">
<UserControl.DataContext>
<local:ViewModelBooks />
</UserControl.DataContext>
<UserControl.Resources>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
<local:Converter x:Key="Converter" />
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</UserControl.Resources>

<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="100" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

<ListView x:Name="tileView" ItemsSource="{Binding BooksToDisplay}" Visibility="{Binding IsTile, Converter={StaticResource Converter}}" Grid.Row="0">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Width="{Binding (FrameworkElement.ActualWidth),
RelativeSource={RelativeSource AncestorType=ScrollContentPresenter}}"
ItemWidth="{Binding (ListView.View).ItemWidth,
RelativeSource={RelativeSource AncestorType=ListView}}"
MinWidth="{Binding ItemWidth, RelativeSource={RelativeSource Self}}"
ItemHeight="{Binding (ListView.View).ItemHeight,
RelativeSource={RelativeSource AncestorType=ListView}}" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<Image Source="{Binding PicUrl}" Width="140" Height="140" Margin="10,10,10,0"/>
<TextBlock Text="{Binding Title}" Width="140" TextAlignment="Center" Margin="10,0,10,10"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>

</ListView>
<ListView Name="listView" Margin="0" ItemsSource="{Binding BooksToDisplay}" Grid.Row="0" Visibility="{Binding IsTile, Converter={StaticResource BooleanToVisibilityConverter}}">
<ListView.View>
<GridView>
<GridViewColumn Header="Titel" Width="Auto" DisplayMemberBinding="{Binding Title}" />
<GridViewColumn Header="Author" Width="Auto" DisplayMemberBinding="{Binding Author}" />
<GridViewColumn Header="Verlag" Width="Auto" DisplayMemberBinding="{Binding Publisher}" />
<GridViewColumn Header="Größe" Width="Auto" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Length}" TextAlignment="Right" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>

</ListView>
<ListView Name="blaView" Margin="0" ItemsSource="{Binding IsTileViewColl, Mode=TwoWay, NotifyOnTargetUpdated=True, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}" Grid.Row="1" >
<ListView.View>
<GridView>
<GridViewColumn Header="Titel" Width="Auto" DisplayMemberBinding="{Binding}" />
</GridView>
</ListView.View>
</ListView>

<TextBlock Text="{Binding IsTile, Mode=TwoWay, NotifyOnTargetUpdated=True, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}" TextAlignment="Left" />

</Grid>
</UserControl>

我也尝试了没有所有额外绑定(bind)属性的 TextBlock。

ViewModelBooks.cs(包含 IsTile-Property):

namespace Bla {
public class ViewModelBooks : INotifyPropertyChanged {

ObservableCollection<Book> _booksToDisplay = new ObservableCollection<Book>();

FileInfo[] _filesTxt;

private readonly string folderPath = "/folder";

public ViewModelBooks() {
Title = "Bücher";
ImgUrl = "/Resources/ic_map_white_24dp_2x.png";
_selectedView = "tiles";

DirectoryInfo di = new DirectoryInfo(folderPath);
_filesTxt = di.GetFiles("*.txt");

foreach (FileInfo file in _filesTxt) {
try {
Convert.ToInt32(file.Name.Split('_')[0]);
_booksToDisplay.Add(new Book(file));
} catch (Exception e) {
}
}
}


private string _selectedView;

public void SwitchView() {
if (_selectedView.Equals("tiles")) {
IsTile = true;
} else {
IsTile = false;
}
}

public string Title {
get; set;
}
public string ImgUrl {
get;
private set;
}
public ObservableCollection<Book> BooksToDisplay {
get => _booksToDisplay;
set => _booksToDisplay = value;
}

public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged([CallerMemberName] string propertyName = null) {
if (PropertyChanged == null)
return;
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}

private bool _isTile;
public bool IsTile {
get {
return _isTile;
}
set {
if (_isTile == value)
return;
_isTile = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsTile"));

}
}

只要菜单命令更新 IsTile,它就可以工作。但更新从未显示在 TextBlock 中

编辑:现在您可以看到完整的 ViewBooks.xamlViewModelBooks.cs。实际上,ViewmodelBooks.cs 也有这段代码(我猜你没兴趣):

public class Book {

string _title;
string _author;
string _publisher;
int _version;
string _url;
string _thumbMD5;
string _fileMD5;
string _areaCode;
string _length;
string _picUrl;

public Book(FileInfo file) {

string oufName = file.FullName.Remove(file.FullName.Length -4, 4) + ".ouf";
FileInfo oufFile = new FileInfo(oufName);
_picUrl = file.FullName.Remove(file.FullName.Length - 4, 4) + ".png";
//_length = string.Format("{0} KB", oufFile.Length >> 10);
float lengthInM = (oufFile.Length >> 10) / 1024f;
_length = lengthInM.ToString("N2") + " MB";

try {
using (StreamReader reader = file.OpenText()) {
string line;

while ((line = reader.ReadLine()) != null) {

string[] lineSeg = line.Split(':');
switch (lineSeg[0]) {
case "Name":
_title = lineSeg[1].Trim();
break;
case "Publisher":
_publisher = lineSeg[1].Trim();
break;
case "Author":
_author = lineSeg[1].Trim();
break;
case "Book Version":
_version = Convert.ToInt32(lineSeg[1].Trim());
break;
case "URL":
_url = lineSeg[1].Trim();
break;
case "ThumbMD5":
_thumbMD5 = lineSeg[1].Trim();
break;
case "FileMD5":
_fileMD5 = lineSeg[1].Trim();
break;
case "Book Area Code":
_areaCode = lineSeg[1].Trim();
break;
}
}
}
} catch (Exception e) {
Debug.WriteLine("ALERT!!! Book-Constructor-Exception: " + e);
}
}

public string Title {
get => _title;
set => _title = value;
}
public string Author {
get => _author;
set => _author = value;
}
public string Publisher {
get => _publisher;
set => _publisher = value;
}
public int Version {
get => _version;
set => _version = value;
}
public string Url {
get => _url;
set => _url = value;
}
public string ThumbMD5 {
get => _thumbMD5;
set => _thumbMD5 = value;
}
public string FileMD5 {
get => _fileMD5;
set => _fileMD5 = value;
}
public string AreaCode {
get => _areaCode;
set => _areaCode = value;
}
public string Length {
get => _length;
set => _length = value;
}
public string PicUrl {
get => _picUrl;
set => _picUrl = value;
}
}
}



class Converter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
return ((bool)value) ? Visibility.Collapsed : Visibility.Visible;
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
throw new NotImplementedException();
}

}
}

最佳答案

问题来了。在 ViewBooks.xaml 中删除它,您应该没问题。

<UserControl.DataContext>
<local:ViewModelBooks />
</UserControl.DataContext>

这就是为什么这是一个问题。您正在尝试使用 ViewBooks 来显示 MainWindowViewModel 的 ViewModelBooks 副本,它是在 MainWindowViewModel 中创建的:

object[] _screens = new object[] { new ViewModelBooks(), new ViewModelMusic() };

因此,您使 ViewModelBooks 实例成为选项卡的内容。您已经为 ViewModelBooks 创建了一个隐式 DataTemplate,它创建了 ViewBooks 的一个副本,并且一切正常。数据模板被实例化,MainWindowViewModel 的ViewModelBooks 副本作为其DataContext。它创建了一个 ViewBooks 实例,该实例应该从 DataTemplate 继承其 DataContext。

<DataTemplate DataType="{x:Type local:ViewModelBooks}">
<local:ViewBooks />
</DataTemplate>

到目前为止一切顺利。这一切都是应该的。

但是 ViewBooks 创建了它自己的 viewmodel 副本,它替换了它应该继承的 DataContext:

<UserControl.DataContext>
<local:ViewModelBooks />
</UserControl.DataContext>

因此,当 MainWindowViewModel 在它自己的 ViewModelBooks 副本上调用方法时,您可以设置一个断点,这似乎有效,因为 MainWindowViewModel 当然有一个完美的 ViewModelBooks 副本——但 UI 中什么也没有显示,因为 您创建了两个 ViewModelBooks 副本,您在 UI 中看到的副本不是 MainWindowViewModel 拥有的副本。

额外学分

顺便说一句,这是在 MainWindowViewModel 中创建这些东西的更好方法:

private ViewModelBooks _vmBooks = new ViewModelBooks();
private ViewModelMusic _vmMusic = new ViewModelMusic();

// Initialized in constructor
object[] _screens;

public MainWindowViewModel()
{
_screens = new object[] { _vmBooks, _vmMusic };

MenuCommand = new RelayCommand(o => {
Debug.WriteLine("Menu Command " + o);
SwitchBooks(o);
});

SelectedItem = "Bla.ViewModelBooks";
}

然后就可以使用属性了。 _screens[0] 的问题是,有一天您可能会更改 _screens 中项目的顺序,然后您将不得不追查对 的每个引用>_screens 并修复它。

    if (o.ToString().Equals("Bla.ViewModelBooks")) 
{
//((ViewModelBooks)_screens[0]).SwitchView();

_vmBooks.SwitchView();
}

此外,我不确定 MenuCommand 从何处获取其参数,但我怀疑您可能会这样做 - 在您进行上述建议的更改后试一试。

    if (o is ViewModelBooks) {
((ViewModelBooks)o).SwitchView();
}

最好的办法是让所有选项卡 View 模型都继承自同一个基类,该基类具有虚拟 SwitchView() 方法:

if (o is TabViewModelBase)
{
((TabViewModelBase)o).SwitchView();
}

然后那个 case 会永远处理每个子选项卡,您永远不必再看那段代码。

关于c# TabControl 不会刷新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43637051/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com