sbprasad

Hi,

I am having problem with listview selection in WPF. I have an listview with the following values and 2 of the values are same.

ListView Items:

1. TestValue1

2. TestValue2

3. TestValue3

4. TestValue4

5. TestValue1

The problem is that when the user selects the first value(TestValue1), the fifth value(TestValue1) also gets selected. Is there any workaround for this problem.

Thanks,

Banu



Re: Windows Presentation Foundation (WPF) ListView Selection Problem

Dr. WPF

The workaround is to not use value types for the data items in your collection (or more specifically, don't use types that determine equality based on a value comparison rather than a reference comparison). In your viewmodel, you can create a reference type that wraps the value and use an observable collection of that type instead.






Re: Windows Presentation Foundation (WPF) ListView Selection Problem

Marlon Grech

another way of doing this is to create a clone of your object.....

Code Block

public class Test : ICloneable

{

private string text;

public string Text

{

get { return text; }

set { text = value; }

}

#region ICloneable Members

public object Clone()

{

return this.MemberwiseClone();

}

#endregion

}

/// <summary>

/// Interaction logic for Window2.xaml

/// </summary>

public partial class Window2 : Window

{

public Window2()

{

InitializeComponent();

Test s = new Test();

s.Text = "hello";

Test a = new Test();

a.Text = "hello2";

testList.Items.Add(s);

testList.Items.Add(a);

testList.Items.Add(s.Clone());

}

}

where testList is your ListView






Re: Windows Presentation Foundation (WPF) ListView Selection Problem

Dr. WPF

Creating a clone is just creating a new instance of the object. This still won't work for types like string that use an equality comparison based on value rather than reference.

To verify this, make your test class use a value comparison by adding the following:

Code Block

#region Equality by Value Comparison

public static bool operator ==(Test t1, Test t2)

{

if ((object)t1 == null)

return (object)t2 == null;

if ((object)t2 == null)

return (object)t1 == null;

return t1.Equals(t2);

}

public static bool operator !=(Test t1, Test t2)

{

return !(t1 == t2);

}

public override int GetHashCode()

{

return text.GetHashCode();

}

public override bool Equals(object o)

{

if (o is Test)

{

return ((Test)o).text == text;

}

return false;

}

#endregion

When you select the third item the first will be selected also. And when you select the second, you'll see that WPF is . When you select the second item, one of the "hello"s will remain selected.

However, your overall approach of creating a wrapper class for the string is definitely the right way to go. This eliminates the value comparison by creating a class that only supports reference comparisons.






Re: Windows Presentation Foundation (WPF) ListView Selection Problem

sbprasad

Thanks for the suggestion. I currently use a business object which contains a property List(Of String) and bind this property to the ListView. so If I create a ObservableCollection and bind it to the ListView, will it solve the problem.





Re: Windows Presentation Foundation (WPF) ListView Selection Problem

Dr. WPF

No, you will still need to wrap each string in an object that supports reference comparisons rather than value comparisons. You could create a RefString class that contains a single member called Value (of type string). You then simply need to override the ToString() method in your class to return _value.ToString(). This will give the object the same behavior as String when presented in a ContentPresenter (such as ListViewItem).

I actually use a RefValue template class in some projects when I need to bind to a collection of value types (or value-comparison types). I've posted it here, if you'd like to borrow it.

This class provides some extra things (like the ContentProperty attribute, dynamic type conversion, and property change notifications for the Value property) that allow it to play nicely in the WPF/XAML world.

With this template class, you can declare a RefString class as follows:

public class RefString : RefValue<string> { }

And a RefInt class would simply be:

public class RefInt : RefValue<int> { }

Then in your markup, you can do this:

Code Block

<ListBox>

<src:RefString>TestValue1</src:RefString>

<src:RefString>TestValue2</src:RefString>

<src:RefString>TestValue3</src:RefString>

<src:RefString>TestValue4</src:RefString>

<src:RefString>TestValue1</src:RefString>

</ListBox>

<ListBox>

<src:RefInt>1</src:RefInt>

<src:RefInt>2</src:RefInt>

<src:RefInt>3</src:RefInt>

<src:RefInt>4</src:RefInt>

<src:RefInt>1</src:RefInt>

</ListBox>

The issue you are up against and the solution I'm proposing will eventually be covered in my "ItemsControl: A to Z" series.