Hi,
I use the RadGridView with a VQCV and dynamic typed data in it. This works fine so far. My problem is, that I want to select the first row after the first set of data was loaded. I get the ItemsLoaded event and set the a SelectedItem property in my ViewModel. This property is bound to the RadGridView but it doesn't render the selected item correct (yellow selection). If I selected rows using the mouse everything works fine, only the programatic selection doesn't work.
I have debugged the issue for a while and wonder that I can see, that the RadGridView has the correct object referenced by the SelectedItem property, but visually the row is not selected.
public
class
MainWindowViewModel : INotifyPropertyChanged
{
private
DynamicDataRow selectedItem;
public
MainWindowViewModel()
{
this
.Data =
new
VirtualQueryableCollectionView { LoadSize = 10, VirtualItemCount = 1000 };
this
.Data.ItemsLoading +=
this
.ViewItemsLoading;
this
.Data.ItemsLoaded +=
this
.ViewItemsLoaded;
}
public
event
PropertyChangedEventHandler PropertyChanged;
public
VirtualQueryableCollectionView Data {
get
;
private
set
; }
public
DynamicDataRow SelectedItem
{
get
{
return
this
.selectedItem;
}
set
{
this
.selectedItem = value;
this
.OnPropertyChanged();
}
}
protected
virtual
void
OnPropertyChanged([CallerMemberName]
string
propertyName =
null
)
{
var handler =
this
.PropertyChanged;
if
(handler !=
null
)
{
handler(
this
,
new
PropertyChangedEventArgs(propertyName));
}
}
private
static
void
GenerateData(List<dynamic> data,
int
startIndex = 0)
{
var random =
new
Random(1000);
for
(
int
i = startIndex; i < startIndex + 10; i++)
{
var row =
new
DynamicDataRow();
row.Add(
"Time"
, DateTime.Now);
row.Add(
"NameD"
,
"Klaus"
+ i);
row.Add(
"Age"
, Convert.ToInt16(random.Next(
short
.MaxValue)));
row.Add(
"Null"
, (
object
)
null
);
row.Add(
"Double"
, Convert.ToDouble(1.3434));
data.Add(row);
}
}
private
void
ViewItemsLoaded(
object
sender, VirtualQueryableCollectionViewItemsLoadedEventArgs e)
{
if
(e.StartIndex == 10)
{
foreach
(DynamicDataRow item
in
e.Items)
{
this
.SelectedItem = item;
break
;
}
}
}
private
void
ViewItemsLoading(
object
sender, VirtualQueryableCollectionViewItemsLoadingEventArgs e)
{
var source = sender
as
VirtualQueryableCollectionView;
if
(source ==
null
)
{
return
;
}
var data =
new
List<dynamic>();
GenerateData(data, e.StartIndex);
source.Load(e.StartIndex, data);
}
}
/// <summary>
/// A collection of dynamic data rows can be used to populate a RadGridView
/// with content if the number of columns is variable and only known during
/// runtime.
/// </summary>
/// <seealso cref="System.Dynamic.DynamicObject" />
public
class
DynamicDataRow : DynamicObject
{
private
readonly
IDictionary<
string
,
object
> data;
/// <summary>
/// Initializes a new instance of the <see cref="DynamicDataRow" /> class.
/// </summary>
public
DynamicDataRow()
{
this
.data =
new
Dictionary<
string
,
object
>();
}
/// <summary>
/// Adds a value to a specified column in the current row.
/// </summary>
/// <param name="columnName">The column name.</param>
/// <param name="value">The value for the cell.</param>
public
void
Add(
string
columnName,
object
value)
{
this
.data[columnName] = value;
}
/// <summary>
/// Call this method to get a list of all column names. The method
/// is used by the RadGridView to generate the columns during runtime-
/// </summary>
/// <returns>
/// A sequence that contains the column names.
/// </returns>
public
override
IEnumerable<
string
> GetDynamicMemberNames()
{
return
this
.data.Keys;
}
/// <summary>
/// Provides the implementation for operations that get member values. Classes derived from
/// the <see cref="T:System.Dynamic.DynamicObject" /> class can override this method to specify
/// dynamic behavior for operations such as getting a value for a property.
/// </summary>
/// <param name="binder">
/// Provides information about the object that called the dynamic operation.
/// The binder.Name property provides the name of the member on which the dynamic operation is
/// performed. For example, for the Console.WriteLine(sampleObject.SampleProperty) statement,
/// where sampleObject is an instance of the class derived from the
/// <see cref="T:System.Dynamic.DynamicObject" /> class, binder.Name returns "SampleProperty".
/// The binder.IgnoreCase property specifies whether the member name is case-sensitive.
/// </param>
/// <param name="result">
/// The result of the get operation. For example, if the method is called
/// for a property, you can assign the property value to <paramref name="result" />.
/// </param>
/// <returns>
/// True if the operation is successful; otherwise, false. If this method returns false, the
/// run-time binder of the language determines the behavior. (In most cases, a run-time
/// exception is thrown.)
/// </returns>
public
override
bool
TryGetMember(GetMemberBinder binder,
out
object
result)
{
result =
this
.data[binder.Name];
return
true
;
}
/// <summary>
/// Provides the implementation for operations that set member values. Classes derived
/// from the <see cref="T:System.Dynamic.DynamicObject" /> class can override this method
/// to specify dynamic behavior for operations such as setting a value for a property.
/// </summary>
/// <param name="binder">
/// Provides information about the object that called the dynamic
/// operation. The binder.Name property provides the name of the member to which the value
/// is being assigned. For example, for the statement sampleObject.SampleProperty = "Test",
/// where sampleObject is an instance of the class derived from the
/// <see cref="T:System.Dynamic.DynamicObject" /> class, binder.Name returns "SampleProperty".
/// The binder.IgnoreCase property specifies whether the member name is case-sensitive.
/// </param>
/// <param name="value">
/// The value to set to the member. For example, for
/// sampleObject.SampleProperty = "Test", where sampleObject is an instance of the class
/// derived from the <see cref="T:System.Dynamic.DynamicObject" /> class, the
/// <paramref name="value" /> is "Test".
/// </param>
/// <returns>
/// True if the operation is successful; otherwise, false. If this method returns false,
/// the run-time binder of the language determines the behavior. (In most cases, a
/// language-specific run-time exception is thrown.)
/// </returns>
public
override
bool
TrySetMember(SetMemberBinder binder,
object
value)
{
this
.data[binder.Name] = value;
return
true
;
}
}
<
Window
x:Class
=
"WPF.RadGridViewVirtualizing.MainWindow"
xmlns:controls
=
"http://schemas.telerik.com/2008/xaml/presentation"
Title
=
"MainWindow"
Height
=
"350"
Width
=
"525"
>
<
Grid
>
<
controls:RadGridView
CanUserReorderColumns
=
"False"
ShowGroupPanel
=
"False"
AutoGenerateColumns
=
"True"
Grid.Row
=
"0"
IsFilteringAllowed
=
"False"
IsReadOnly
=
"True"
GridLinesVisibility
=
"Both"
SelectionMode
=
"Extended"
SelectionUnit
=
"FullRow"
RowIndicatorVisibility
=
"Collapsed"
AlternationCount
=
"2"
AlternateRowBackground
=
"#F2F2F2"
ItemsSource
=
"{Binding Data}"
SelectedItem
=
"{Binding SelectedItem}"
CanUserFreezeColumns
=
"False"
/>
</
Grid
>
</
Window
>
I tried to attach a small project which reproduces the problem, but zip was not allowed :(
Thanks
Michael