Создание универсальной процедуры синхронизции (маршалинга) из нескольких конкретных
имеются синхронизирующие процедура, каждая из которых выполняет одну свою функцию:
If Myobject.InvokeRequired Then
Myobject.Invoke(New UpdateOb(AddressOf TextSet), Myobject, value)
Else
Myobject.Text = value
End If
End Sub
Public Sub TextAdd(ByVal Myobject As Object, ByVal value As String)
If Myobject.InvokeRequired Then
Myobject.Invoke(New UpdateOb(AddressOf TextAdd), Myobject, value)
Else
Myobject.Text &= value
End If
End Sub
Public Sub EnableSet(ByVal Myobject As Object, ByVal value As String)
If Myobject.InvokeRequired Then
Myobject.Invoke(New UpdateOb(AddressOf EnableSet), Myobject, value)
Else
Myobject.Enabled = CBool(value)
End If
End Sub
Public Sub IndexSet(ByVal Myobject As Object, ByVal value As String)
If Myobject.InvokeRequired Then
Myobject.Invoke(New UpdateOb(AddressOf IndexSet), Myobject, value)
Else
Myobject.SelectedIndex = value
End If
End Sub
Необходимо их превратить в одну универсалбну, которой передается объект, свойство и его значение, а потом процедура выполняет:
Я пытался сделать так:
Делегат:
Процедура:
If Myobject.InvokeRequired Then
Myobject.Invoke(New UpdateOb(AddressOf Changing), Myobject, prop, value)
Else
prop = value
End If
End Sub
и вызываю потом так:
prop специально передаю по ссылке (ByRef prop As String), чтобы изменения над prop отражались и на свойстве объекта. Но этого не происходит, свойство не изменяется. Как правильно сделать универсальную синхронизирующую процедуру, как передавать её свойство (ну или метод), которое я хочу изенить (или выполнить).
P.S. Я знаю, что задрал своими ламерскими вопросами (особенно hardcase'а), но в поиске это не напишешь, а сам разобраться не могу. Поверьте, себе моСк я рушу больше, чем вам:D
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Reflection;
namespace WindowsApplication2 {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
SetPropertySync(button1, "Text", "New button text"); // вот так использовать
}
private void SetPropertySync(object obj, string property_name, object new_value) {
if (InvokeRequired) {
Invoke((ThreadStart)delegate {
SetPropertySync(obj, property_name, new_value);
});
} else {
SetProperty(obj, property_name, new_value);
}
}
public static void SetProperty(object obj, string property_name, object new_value) {
Type obj_type = obj.GetType();
PropertyInfo property = obj_type.GetProperty(property_name, BindingFlags.Public | BindingFlags.Instance);
property.SetValue(obj, new_value, null);
}
}
}
Точно также, как и со свойствами.
Вместо GetProperty будет GetMethod, вместо PropertyInfo будет MethodInfo. Остальное нароете :)
Но вот все-таки мне кажется, лучше вам в чате использовать интерфейсы и сериализацию (xml-ню или двоичную).
P.S. с методами так и до конца не разобрался....
Вот класс, в котором собрал методы для динамического обращения к свойствам (с синхронизацией с компонентой) и вызова методов:
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Reflection;
namespace WindowsApplication1 {
public static class DynamicExecutor {
public static void SetProperty(Control control, object obj, string property_name, object new_value) {
if (control.InvokeRequired) {
control.Invoke((ThreadStart)delegate {
SetProperty(obj, property_name, new_value);
});
} else {
SetProperty(obj, property_name, new_value);
}
}
public static void SetProperty(object obj, string property_name, object new_value) {
if(obj == null)
throw new ArgumentNullException("obj");
Type obj_type = obj.GetType();
PropertyInfo property = obj_type.GetProperty(property_name, BindingFlags.Public | BindingFlags.Instance);
if(property == null)
throw new InvalidOperationException(string.Format("Property '{0}' not found in class '{1}.", property_name, obj_type));
property.SetValue(obj, new_value, null);
}
public static void InvokeMethod(Control control, object obj, string method_name, params object[] args) {
if (control.InvokeRequired) {
control.Invoke((ThreadStart)delegate {
InvokeMethod(obj, method_name, args);
});
} else {
InvokeMethod(obj, method_name, args);
}
}
public static void InvokeMethod(object obj, string method_name, params object[] args) {
if (obj == null)
throw new ArgumentNullException("obj");
Type obj_type = obj.GetType();
Type[] arg_types = Array.ConvertAll<object, Type>(args, delegate(object arg) {
return arg != null ? arg.GetType() : typeof(void);
});
MethodInfo method = obj_type.GetMethod(method_name, BindingFlags.Public | BindingFlags.Instance, null, arg_types, null);
if (method == null)
throw new InvalidOperationException(string.Format("Method '{0}' not found in class '{1}.", method_name, obj_type));
method.Invoke(obj, args);
}
}
}
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace WindowsApplication1 {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
DynamicExecutor.SetProperty(this, button1, "Text", "New button text");
}
private void button1_Click(object sender, EventArgs e) {
DynamicExecutor.InvokeMethod(this, this, "Foo", "Hello!", 10, null);
}
public void Foo(string arg1, int arg2, object arg3) {
MessageBox.Show(string.Format("arg1: {0}, arg2: {1}, arg3: {2}", arg1, arg2, arg3));
}
}
}
Дополнил класс семейством функций GetProperty:
public static void SetProperty(Control control, object obj, string property_name, object new_value) {
if (control.InvokeRequired) {
control.Invoke((ThreadStart)delegate {
SetProperty(obj, property_name, new_value);
});
} else {
SetProperty(obj, property_name, new_value);
}
}
public static void SetProperty(object obj, string property_name, object new_value) {
if (obj == null)
throw new ArgumentNullException("obj");
Type obj_type = obj.GetType();
PropertyInfo property = obj_type.GetProperty(property_name, BindingFlags.Public | BindingFlags.Instance);
if (property == null)
throw new InvalidOperationException(string.Format("Property '{0}' not found in class '{1}.", property_name, obj_type));
property.SetValue(obj, new_value, null);
}
public static object GetProperty(Control control, object obj, string property_name) {
if (control.InvokeRequired) {
object result = null;
control.Invoke((ThreadStart)delegate {
result = GetProperty(obj, property_name);
});
return result;
} else {
return GetProperty(obj, property_name);
}
}
public static T GetProperty<T>(Control control, object obj, string property_name) {
if (control.InvokeRequired) {
T result = default(T);
control.Invoke((ThreadStart)delegate {
result = GetProperty<T>(obj, property_name);
});
return result;
} else {
return GetProperty<T>(obj, property_name);
}
}
public static object GetProperty(object obj, string property_name) {
if (obj == null)
throw new ArgumentNullException("obj");
Type obj_type = obj.GetType();
PropertyInfo property = obj_type.GetProperty(property_name, BindingFlags.Public | BindingFlags.Instance);
if (property == null)
throw new InvalidOperationException(string.Format("Property '{0}' not found in class '{1}.", property_name, obj_type));
return property.GetValue(obj, null);
}
public static T GetProperty<T>(object obj, string property_name) {
return (T)GetProperty(obj, property_name);
}
public static void InvokeMethod(Control control, object obj, string method_name, params object[] args) {
if (control.InvokeRequired) {
control.Invoke((ThreadStart)delegate {
InvokeMethod(obj, method_name, args);
});
} else {
InvokeMethod(obj, method_name, args);
}
}
public static void InvokeMethod(object obj, string method_name, params object[] args) {
if (obj == null)
throw new ArgumentNullException("obj");
Type obj_type = obj.GetType();
Type[] arg_types = Array.ConvertAll<object, Type>(args, delegate(object arg) {
return arg != null ? arg.GetType() : typeof(void);
});
MethodInfo method = obj_type.GetMethod(method_name, BindingFlags.Public | BindingFlags.Instance, null, arg_types, null);
if (method == null)
throw new InvalidOperationException(string.Format("Method '{0}' not found in class '{1}.", method_name, obj_type));
method.Invoke(obj, args);
}
}
Я думаю будет проще, если перед запуском потока построить список из имен файлов, подлежащих переименованию, и уже его передавать в поток. Таким образом можно вообще не синхронизирваться с интерфейсом. Поток можно даже оформить в виде бэграунд воркера (BackgroundWoker).
P.S. Я сначала делал через Background Worker, но столкнулся точно также с передачей User-state объекта в Do_Work... возникало исключение, мол чужой поток.... я привык к обычным потокам....
Добавяю... Сделал так:
в классе формы объявил:
потом заполнил:
по нажатию кнопки:
foreach(ListViewItem item in lviewFilmIn.CheckedItems) lst.Add(item.Text);
thr = new Thread(search);
thr.IsBackground = true;
thr.Start();
и вроде работает...
Что-то немного не догоняю...Типы по-значению чужими в другом потоке не считаются, а по-ссылке считаются? или как?
Поясню. Принадлежность тому или иному потоку - это уже фичи, навернутые в строго определенных иерархиях классов. Это техника "контекстно ограниченных объектов" (используется повсеместно в дотнете). В WinForms это все классы, наследованные от Control (кароче - все оконные компоненты), грубо говоря они своим контекстом считают поток, в котором были созданы.