问题描述
我为数据库制作了一个工具,该工具显示带有某些过滤选项的项目。但是,在阅读了有关WPF和C#的更多信息之后。我使用了此https://www.codeproject.com/Articles/683429/Guide-to-WPF-DataGrid-formatting-using-bindings教程来修改我的应用程序以处理pv.exe
我之前曾用它进行过滤:
import {
StyleSheet,Text,View,SafeAreaView,FlatList,Image,TouchableOpacity,Modal,TouchableHighlight,} from "react-native";
import { Colors } from "../colors/Colors";
const DATA = [
{
id: "1",title: "Calves and Hamstrings: one",section: "Stretches",image: require("../assets/S1.png"),modalTitle: "Calves and Hamstrings: one",modalDesc:
"Lorem ipsum dolor sit amet,consectetur adipiscing elit,sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",},{
id: "2",title: "Adductors: one",image: require("../assets/S2.png"),modalTitle: "Adductors: one",{
id: "3",title: "Adductors: two",image: require("../assets/S3.png"),modalTitle: "Adductors: two",{
id: "4",title: "Hip Flexors",image: require("../assets/S4.png"),modalTitle: "Hip Flexors",{
id: "5",title: "Calves and Hamstrings: two",image: require("../assets/S5.png"),modalTitle: "Calves and Hamstrings: two",{
id: "6",title: "Quads",image: require("../assets/S6.png"),modalTitle: "Quads",{
id: "7",title: "Calves and Hamstrings: three",image: require("../assets/S7.png"),modalTitle: "Calves and Hamstrings: three",{
id: "8",title: "glutes (Bum)",image: require("../assets/S8.png"),modalTitle: "glutes (Bum)",{
id: "9",title: "Abs",image: require("../assets/S9.png"),modalTitle: "Abs",{
id: "10",title: "Lats (Sides)",image: require("../assets/S10.png"),modalTitle: "Lats (Sides)",{
id: "11",title: "Deltoid (Shoulder)",image: require("../assets/S11.png"),modalTitle: "Deltoid (Shoulder)",{
id: "12",title: "Triceps",image: require("../assets/S12.png"),modalTitle: "Triceps",{
id: "13",title: "pecs (Chest)",image: require("../assets/S13.png"),modalTitle: "pecs (Chest)",];
export default function StretchesScreen() {
const [modalVisible,setModalVisible] = useState(false);
const [modalDesc,setModalDesc] = useState([]);
const [modalTitle,setModalTitle] = useState("");
const Item = ({ title,image,section,modalTitle,modalDesc }) => (
<View style={styles.item}>
<Image source={image} style={styles.exerciseImage} />
<View style={styles.detailSection}>
<Text style={styles.title}>{title}</Text>
<Text style={styles.section}>{section}</Text>
</View>
<TouchableOpacity
style={styles.viewButton}
onPress={() => {
openSettingsModal(modalTitle,modalDesc);
}}
>
<Text style={styles.viewText}>View</Text>
</TouchableOpacity>
</View>
);
const renderItem = ({ item }) => (
<Item title={item.title} image={item.image} section={item.section} />
);
const openSettingsModal = (modalTitle,modalDesc) => {
setModalTitle(modalTitle);
setModalDesc(modalDesc);
setModalVisible(!modalVisible);
};
return (
<SafeAreaView style={styles.container}>
<View style={styles.tabBackground}>
<Text style={styles.subTitle}>EXERCISES: STRETCHES</Text>
</View>
<Modal
animationType="slide"
transparent={true}
visible={modalVisible}
onRequestClose={() => {
Alert.alert("Modal has been closed.");
}}
>
<View style={styles.centeredView}>
<View style={styles.modalView}>
<Text style={styles.modalText}>{modalTitle}</Text>
<Text style={styles.modalText}>{modalDesc}</Text>
<TouchableHighlight
style={{ ...styles.openButton,backgroundColor: "#2196F3" }}
onPress={() => {
setModalVisible(!modalVisible);
}}
>
<Text style={styles.textStyle}>Hide Modal</Text>
</TouchableHighlight>
</View>
</View>
</Modal>
<FlatList
data={DATA}
renderItem={renderItem}
keyExtractor={(item) => item.id}
/>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,backgroundColor: "#fff",alignItems: "center",justifyContent: "center",tabBackground: {
backgroundColor: Colors.primary,width: "100%",height: "10%",top: 0,left: 0,subTitle: {
position: "absolute",color: "white",fontSize: 10,item: {
padding: 20,backgroundColor: "#FFF",width: "90%",flex: 1,alignSelf: "center",flexDirection: "row",borderRadius: 5,borderBottomWidth: 1,borderColor: Colors.greyLight,exerciseImage: {
width: "20%",height: 60,borderRadius: 30,marginRight: 30,detailSection: {
width: "50%",marginRight: 10,title: {
fontSize: 12,section: {
fontSize: 10,viewButton: {
height: 40,width: "30%",borderWidth: 1,borderColor: Colors.greyMedium,borderRadius: 3,viewText: {
left: 0,centeredView: {
flex: 1,marginTop: 22,modalView: {
margin: 20,backgroundColor: "white",borderRadius: 20,padding: 35,shadowColor: "#000",shadowOffset: {
width: 0,height: 2,shadowOpacity: 0.25,shadowRadius: 3.84,elevation: 5,openButton: {
backgroundColor: "#F194FF",padding: 10,elevation: 2,textStyle: {
color: "white",fontWeight: "bold",textAlign: "center",modalText: {
textAlign: "center",});
然后这样:
ItemCollectionViewSource
但是看来我现在需要使用 public void FilterSetup()
{
try
{
string qry = null;
_conditions["name"] = null;
if (!string.IsNullOrEmpty(BusinessIDSearch.Text))
{
qry = string.Format("LY Like '{0}%'",BusinessIDSearch.Text);
}
if (!string.IsNullOrEmpty(NameSearch.Text))
{
if (!string.IsNullOrEmpty(qry))
qry += " AND ";
qry += string.Format("HAKUNIMI Like '%{0}%'",NameSearch.Text);
}
if (!string.IsNullOrEmpty(GroupSearch.Text))
{
if (!string.IsNullOrEmpty(qry))
qry += " AND ";
qry += string.Format("KONSERNI Like '{0}%'",GroupSearch.Text);
}
if (!string.IsNullOrEmpty(LiinosIDSearch.Text))
{
if (!string.IsNullOrEmpty(qry))
qry += " AND ";
qry += string.Format("YRNRO Like '{0}%'",LiinosIDSearch.Text);
}
_conditions["name"] = qry;
Updatefilter();
//LiinosFICount.Content = DataGrid1.Items.Count;
}
catch (Exception)
{
throw;
}
}
的另一种方法。
这是文本框的XAML部分:
private void Updatefilter()
{
try
{
var activeConditions = _conditions.Where(c => c.Value != null).Select(c => "(" + c.Value + ")");
DataView dv = DataGrid1.ItemsSource as DataView;
dv.RowFilter = string.Join(" AND ",activeConditions);
}
catch (Exception)
{
//MessageBox.Show(ex.Message);
}
}
这里是DataGrid的XAML:
ItemCollectionViewSource
我尝试了一些教程,但没有成功。是否有人可以提供任何类型的教程来建议或提供解决方案,我也可以对其他TextBox实施该解决方案?棘手的是我有几个TextBoxes,我需要根据TextBoxes中的值组合过滤查询。
如您所见,我已尝试在此处应用绑定:
<TextBox Style="{StaticResource TextBox_Style}" x:Name="GroupSearch" HorizontalAlignment="Left" Margin="414,121,0" textwrapping="Wrap" Text="" VerticalAlignment="Top" Width="90" Height="20" TextChanged="GroupSearch_TextChanged"/>
<TextBox Style="{StaticResource TextBox_Style}" x:Name="NameSearch" HorizontalAlignment="Left" Margin="130,0" textwrapping="Wrap" Text="" VerticalAlignment="Top" Width="279" Height="20" TextChanged="NameSearch_TextChanged"/>
<TextBox Style="{StaticResource TextBox_Style}" Text="{Binding FilterString,UpdateSourceTrigger=PropertyChanged}" x:Name="LiinosIDSearch" HorizontalAlignment="Left" Margin="20,0" textwrapping="Wrap" VerticalAlignment="Top" Width="105" Height="20"/>
<TextBox Style="{StaticResource TextBox_Style}" x:Name="BusinessIDSearch" HorizontalAlignment="Left" Margin="509,0" textwrapping="Wrap" Text="" VerticalAlignment="Top" Width="192" Height="20" TextChanged="BusinessIDSearch_TextChanged"/>
我从一些教程中获得了此信息,并尝试将其修改为我的需要而没有成功:
<DataGrid Margin="0,146,0" Background="{x:Null}" BorderBrush="{x:Null}"
CanUserAddRows="False" CanUserDeleteRows="False" CanUserResizeRows="False" IsReadOnly="True"
HorizontalGridLinesBrush="#FF377A6C" VerticalGridLinesBrush="#FF377A6C"
DataContext="{StaticResource ItemCollectionViewSource}"
ItemsSource="{Binding}"
AutoGenerateColumns="False" FontFamily="Arial Nova" Foreground="White" >
<DataGrid.RowStyle>
<Style targettype="DataGridRow" >
<Setter Property="Background" Value="{Binding YRNRO,Converter={StaticResource LiinosIDToBackgroundConverter}}" />
</Style>
</DataGrid.RowStyle>
<DataGrid.Resources>
<Style BasedOn="{StaticResource {x:Type DataGridColumnHeader}}" targettype="{x:Type DataGridColumnHeader}">
<Setter Property="Background" Value="#377A6C" />
<Setter Property="Foreground" Value="White" />
<Setter Property="MinHeight" Value="20" />
</Style>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
Color="#5AC37E"/>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding YRNRO}">
<DataGridTextColumn.Header>
<TextBlock Text="LIINOS ID" FontWeight="Bold" TextAlignment="Left"/>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding HAKUNIMI}">
<DataGridTextColumn.Header>
<TextBlock Text="SEARCH NAME" FontWeight="Bold" TextAlignment="Left"/>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding KONSERNI}">
<DataGridTextColumn.Header>
<TextBlock Text="GROUP" FontWeight="Bold" TextAlignment="Left"/>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding LY}">
<DataGridTextColumn.Header>
<TextBlock Text="BUSInesS ID" FontWeight="Bold" TextAlignment="Left"/>
</DataGridTextColumn.Header>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
编辑:
我正在将当前单击按钮上的数据加载到DataGrid:
<TextBox Style="{StaticResource TextBox_Style}" Text="{Binding FilterString,0" textwrapping="Wrap" VerticalAlignment="Top" Width="105" Height="20"/>
编辑2:
这是我一直在使用的using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Windows.Data;
namespace Liinos_inspector_FilterTest
{
public class viewmodel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _filter1 = "";
private string _filter2 = "";
private string _filter3 = "";
public viewmodel()
{
var List = MainProcess.CustomersInLiinos.AsEnumerable()
.GroupBy(x => x.Field<string>("HAKUNIMI"))
.Where(x => x.Count() > 1)
.SelectMany(x => x)
.ToList();
//ItemList = new ObservableCollection<Items>(List);
ItemView = (CollectionView)CollectionViewSource.Getdefaultview(List);
ItemView.Filter = TextFilter;
}
private bool TextFilter(object obj)
{
var data = obj as Items;
if (data != null)
{
return data.Text1.StartsWith(_filter1) && data.Text2.StartsWith(_filter2) && data.Text3.StartsWith(_filter3);
}
return false;
}
private void NotifyPropertyChanged(string property)
{
PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(property));
}
public ObservableCollection<Items> ItemList { get; set; }
public CollectionView ItemView { get; set; }
public string Filter1
{
get { return _filter1; }
set
{
_filter1 = value;
NotifyPropertyChanged("Filter1");
ItemView.Refresh();
}
}
public string Filter2
{
get { return _filter2; }
set
{
_filter2 = value;
NotifyPropertyChanged("Filter2");
ItemView.Refresh();
}
}
public string Filter3
{
get { return _filter3; }
set
{
_filter3 = value;
NotifyPropertyChanged("Filter3");
ItemView.Refresh();
}
}
}
public class Items
{
public string Text1 { get; set; }
public string Text2 { get; set; }
public string Text3 { get; set; }
}
}
方法:
private async void Button_Click_1(object sender,RoutedEventArgs e)
{
if (MainProcess.CheckForVPNInterface() == true)
{
if (MainProcess.Customers != null)
{
ProgressBar.IsIndeterminate = true;
CollectionViewSource itemCollectionViewSource;
itemCollectionViewSource = (CollectionViewSource)(FindResource("ItemCollectionViewSource"));
itemCollectionViewSource.source = await LoadMainTableDataAsync();
ProgressBar.IsIndeterminate = false;
}
}
else
{
string caption = "VPN connection missing";
MessageBox.Show("Please,check your VPN connection!",caption,MessageBoxButton.OK,MessageBoxImage.Exclamation);
}
}
这里是数据表的合并:
LoadMainTableDataAsync
解决方法
您不需要CollectionViewSource
即可过滤集合。只需绑定到视图模型的集合即可。在WPF中,集合是通过引擎盖下的ICollectionsView
消耗的。每个集合都返回一个默认视图。控件在此视图上自动运行。要更改顺序,分组或过滤,请修改集合的当前视图,而不是实际的集合实例。
另外,请勿将DataContext
显式设置为CollectionViewSource
。直接绑定到它。
请注意,由于绑定到模型项,Items
应该实现INotifyPropertyChanged
或引发内存泄漏。
请勿在视图模型中处理ProgressBar
。设置一个bool
属性并将其绑定到ProgressBar.Visibility
。
为了处理异常,不会在视图模型中显示MessageBox
或任何用户对话框。而是抛出一个有意义的完全自定义异常或包装异常(原始异常作为内部异常)并在您的视图中处理它,例如,通过显示一个交互对话框。
在您的视图中不处理数据库或任何其他数据(模型)访问。而是实现ICommand
并将其分配给按钮以替换事件处理程序,并在视图模型中执行操作。有关RelayCommand
的简单实现,请参见Microsoft Docs: Relaying Command Logic。
这是一个基本示例,其中介绍了如何使用集合的默认ICollectionView
来过滤集合,并结合了建议的改进。您需要根据需要调整实际的过滤器逻辑:
VpnInterfaceException.cs
class VpnInterfaceException : Exception
{
public VpnInterfaceException(string message) : base(message)
{
}
public VpnInterfaceException(string message,Exception innerException) : base(message,innerException)
{
}
}
Item.cs
class Item : INotifyPropertyChanged
{
private string text;
public string Text
{
get => this.text;
set
{
this.text = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(propertyName));
}
}
ViewModel.cs
class ViewModel : INotifyPropertyChanged
{
public ObservableCollection<Item> Items { get; set; }
public ICommand LoadMainTableDataCommand => new RelayCommand(ExecuteLoadMainTableDataAsync);
// Binding source for the TextBox
private string searchKey;
public string SearchKey
{
get => this.searchKey;
set
{
this.searchKey = value;
OnPropertyChanged();
// Refresh the ICollectionView to update the filter expression
CollectionViewSource.GetDefaultView(this.Items).Refresh();
}
}
private bool hasProgress;
public bool HasProgress
{
get => this.hasProgress;
set
{
this.hasProgress = value;
OnPropertyChanged();
}
}
public ViewModel()
{
this.Items = new ObservableCollection<Item>();
EnableItemsFiltering();
}
public void EnableItemsFiltering()
{
// Assign the filter expression which is executed when items are added
// or the 'ICollectionView.Refresh()' was called
CollectionViewSource.GetDefaultView(this.Items).Filter = FilterPredicate;
}
// The filter expression.
// Returns 'true' to include the current item.
private bool FilterPredicate(object item)
=> string.IsNullOrWhiteSpace(this.SearchKey)
|| ((item as Item)?.Text.StartsWith(this.SearchKey,StringComparison.OrdinalIgnoreCase) ?? false);
private async Task ExecuteLoadMainTableDataAsync(object commandParameter)
{
if (MainProcess.CheckForVPNInterface())
{
if (MainProcess.Customers != null)
{
this.HasProgress = true;
IEnumerable<Item> resultItems = await LoadMainTableDataAsync();
this.Items = new ObservableCollection<Item>(resultItems);
EnableItemsFiltering();
this.HasProgress = false;
}
}
else
{
// Throw an exception since the operation cannot be completed unexpectedly.
// The view can catch this exception to execute the error handling.
throw new VpnInterfaceException("Please,check your VPN connection!");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
=> this.PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(propertyName));
}
MainWindow.xaml.cs
partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// Handle specific view model exceptions for user interaction
this.Dispatcher.UnhandledException += (sender,args) =>
{
// Only handle selected exceptions,that can be handled through user interaction
if (args.Exception is VpnInterfaceException exception)
{
args.Handled = true;
string caption = "VPN connection missing";
// Convert exception message to user friendly message
MessageBox.Show(exception.Message,caption,MessageBoxButton.OK,MessageBoxImage.Exclamation);
}
};
}
}
MainWindow.xaml
<Window>
<Window.DataContext>
<ViewModel />
</Window.DataContext>
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Window.Resources>
<StackPanel>
<ProgressBar IsIndeterminate="True"
Visibility="{Binding HasProgress,Converter={StaticResource BooleanToVisibilityConverter}}" />
<Button Command="{Binding LoadMainTableDataCommand}"
Content="Load Data" />
<TextBox Text="{Binding SearchKey}" />
<DataGrid ItemsSource="{Binding Items}" />
<StackPanel>
</Window>