Rodonies
Rodonies
CC#
Created by Rodonies on 9/26/2024 in #help
WPF CollectionView Filter on Property of Model?
in a MVVM WPF app, how would I go about filtering a ListBox that is bound to a property of a model?
//Model
class Y {
string Name;
List<X> ListOfX;
}

class X {
string Name;
}
//Model
class Y {
string Name;
List<X> ListOfX;
}

class X {
string Name;
}
//ViewModel
public ObservableCollection<Y> ObservableListOfY { get; set; }


private Y _SelectedY;
public Y SelectedY;
{
get { return _SelectedY; }
set
{
_SelectedY = value;
OnPropertyChanged();
}
}

private string _SearchBoxText = string.Empty;
public string SearchBoxText
{
get { return SearchBoxText; }
set
{
_SearchBoxText = value;
FilterData();
OnPropertyChanged();
}
}

public ctor()
{
ObservableListOfY = ...
}

public void FilterData()
{
//This filter works
CollectionViewSource.GetDefaultView(ObservableListOfY ).Filter = o => (o as Y).ListOfX.Any(x => x.Name.Contains(SearchBoxText));

//This one doesn't, probably because ListOfZ is not an ObservableCollection
CollectionViewSource.GetDefaultView(SelectedY.ListOfZ).Filter = o => (o as X).Name.Contains(SearchBoxText);
}
//ViewModel
public ObservableCollection<Y> ObservableListOfY { get; set; }


private Y _SelectedY;
public Y SelectedY;
{
get { return _SelectedY; }
set
{
_SelectedY = value;
OnPropertyChanged();
}
}

private string _SearchBoxText = string.Empty;
public string SearchBoxText
{
get { return SearchBoxText; }
set
{
_SearchBoxText = value;
FilterData();
OnPropertyChanged();
}
}

public ctor()
{
ObservableListOfY = ...
}

public void FilterData()
{
//This filter works
CollectionViewSource.GetDefaultView(ObservableListOfY ).Filter = o => (o as Y).ListOfX.Any(x => x.Name.Contains(SearchBoxText));

//This one doesn't, probably because ListOfZ is not an ObservableCollection
CollectionViewSource.GetDefaultView(SelectedY.ListOfZ).Filter = o => (o as X).Name.Contains(SearchBoxText);
}
<!--View-->
<TextBox Text="{Binding SearchBoxText}" />
<ListBox ItemsSource="{Binding ObservableListOfY}" SelectedItem="{Binding SelectedY}" />
<ListBox ItemsSource="{Binding SelectedY.ListOfX}" />
<!--View-->
<TextBox Text="{Binding SearchBoxText}" />
<ListBox ItemsSource="{Binding ObservableListOfY}" SelectedItem="{Binding SelectedY}" />
<ListBox ItemsSource="{Binding SelectedY.ListOfX}" />
I want to filter out all the Y's that don't have a single X that matches the SearchText, I achieve this by setting the Filter property on YCollectionView in the ViewModel. The problem is that even though that works, if you select a Y in the listbox it'll show every X, even if they don't match the text. I can't set the Filter property on a CollectionView because ListOfX is a property of the Y model and I don't think I should use a CollectionView in the model, how would you normally achieve this behaviour? is creating a ObservableListOfX and updating it in the setter of SelectedY a valid solution?
22 replies
CC#
Created by Rodonies on 9/16/2024 in #help
WPF Framework Canvas Automatic Scaling based on largest coordinate in list
Hi. First of all, thank you for reading! I have a MVVM WPF application and having some trouble with the Canvas and how to draw shapes that are automatically scaled to the canvas size. Let's say I have a model Y that contains a list of X. X has a location and my goal is to display all X's in a fixed size canvas using circles. The location of each X can vary wildly so for every list of X that gets selected I need to use the largest coordinate of the furthest X in that list to scale it so all the X's show up properly on the canvas, the furthest one should be located 10% away from the canvas' border. Assuming (0, 0) is the middle of my canvas the calculation for this should be
coordinate/(FurthestCoordinate/(0.9*CanvasSize/2))
coordinate/(FurthestCoordinate/(0.9*CanvasSize/2))
I am using the CalcBinding nuget so I can do calculations in my binding, like so:
{c:Binding (Location.X*6)+500}
{c:Binding (Location.X*6)+500}
The problem: I can't seem to use the LargestCoordinate property from the ancestor (which is Y) in my calculation for each X I can get that property in xaml correctly using:
{Binding Path=DataContext.LargestCoordinate, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Border}, Mode=OneWay}
{Binding Path=DataContext.LargestCoordinate, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Border}, Mode=OneWay}
but cannot use this method in my full calculation:
X="{c:Binding '(Location.X/({Binding Path=DataContext.LargestCoordinate, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Border}, Mode=OneWay}/(0.45*494))'}"
X="{c:Binding '(Location.X/({Binding Path=DataContext.LargestCoordinate, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Border}, Mode=OneWay}/(0.45*494))'}"
it just gives a whole lot of XAML binding errors like this one:
System.Windows.Data Warning: 40 : BindingExpression path error: 'FindAncestor' property not found on 'object' ''Planet' (HashCode=19050756)'. BindingExpression:Path=FindAncestor; DataItem='Planet' (HashCode=19050756); target element is 'TranslateTransform' (HashCode=48896832); target property is 'X' (type 'Double')
Is there any way I can use the LargestCoordinate property from Y in my calculation for each X so I can scale the locations properly?
7 replies