|
Not like that but you can write code that will at runtime construct an object of a generic, at runtime determined type.
If the brain were so simple we could understand it, we would be so simple we couldn't. — Lyall Watson
|
|
|
|
|
Yes. Using reflection to create the generics itself...
I'm not sure I want to see code such that...
(Type.MakeGenericType Method (Type[]) (System)[^])
Skipper: We'll fix it.
Alex: Fix it? How you gonna fix this?
Skipper: Grit, spit and a whole lotta duct tape.
|
|
|
|
|
It's a lot of fun
If the brain were so simple we could understand it, we would be so simple we couldn't. — Lyall Watson
|
|
|
|
|
Yeah, I couldn't make it compile, it was just a way of showing what I tried to do. I thought, surely it must be possible to do in one way or another.
In fact, why don't you reflect upon that
|
|
|
|
|
Don't call me Shirley!!!
Sure it is possible not in one way, but another...but that another way is messy a bit...
You know where it begins, but can't see the end...[^]
Skipper: We'll fix it.
Alex: Fix it? How you gonna fix this?
Skipper: Grit, spit and a whole lotta duct tape.
|
|
|
|
|
|
I'm not familiar with WPF and PropertyDescriptor, so this might not be all you need but I think it'll get you a step further. I simplified it a bit so that I could test it in a new WPF-project. Note that you need a generic EventHandler for the AddHandler(..)-call and that you need to provide the name of the event there, not the name of the property:
public MainWindow()
{
InitializeComponent();
object sender = this;
WeakReference _sender = new WeakReference(sender);
EventHandler<EventArgs> handler = (s, e) => this.Title += ".";
string eventName = "MouseMove";
Type unboundWEMType = typeof(WeakEventManager<,>);
Type[] typeArgs = { _sender.Target.GetType(), typeof(EventArgs) };
Type constructedWEMType = unboundWEMType.MakeGenericType(typeArgs);
MethodInfo addHandlerMethod = constructedWEMType.GetMethod("AddHandler");
addHandlerMethod.Invoke(null, new object[] { _sender.Target, eventName, handler });
}
If the brain were so simple we could understand it, we would be so simple we couldn't. — Lyall Watson
|
|
|
|
|
This looks very promising indeed. This piece of code is intended to be used in a Mediator, i.a a static instance that you can use to synchronize two or more properties in separate classes. The code is very similar to Sacha Barbers Mediator in his MVVM helper class Cinch, where you can raise an event in a property and it will invoke a delegate to a subroutine (void) in a separate class (in my cases between two ViewModels). I want to change the behavior to update a property if another property changed. The problem is that the connections with the shared (static) Mediator must be of a weak type, if not you might get a lot of memory leaks as a direct consequence of the strong references the normal event creates.
To do this I created an attribute that you can decorate a property with:
[AttributeUsage(AttributeTargets.Property)]
public sealed class PropertyMediatorAttribute : Attribute
{
public string MessageKey { get; private set; }
public PropertyMediatorAttribute()
{
MessageKey = null;
}
public PropertyMediatorAttribute(string messageKey)
{
MessageKey = messageKey;
}
}
My full code so far is (it does work but it won't allow the connected classes to be garbage collected):
public class PropertyMediator
{
#region Data
static readonly PropertyMediator instance = new PropertyMediator();
static readonly object syncLock = new object();
private readonly Dictionary<string, List<WeakPropertyDescriptor>> _registeredListners =
new Dictionary<string, List<WeakPropertyDescriptor>>();
#endregion
#region Ctor
static PropertyMediator()
{
}
private PropertyMediator()
{
}
#endregion
public static PropertyMediator Instance
{
get
{
return instance;
}
}
internal class WeakPropertyDescriptor
{
public PropertyMediator _MethodOwner;
public WeakReference _sender;
public string _PropertyName;
public string _MessageKey;
public EventHandler handler;
public WeakPropertyDescriptor(PropertyMediator MethodOwner, Object sender, string PropertyName, string MessageKey)
{
_MethodOwner = MethodOwner;
_sender = new WeakReference(sender);
_PropertyName = PropertyName;
_MessageKey = MessageKey;
handler = (s, e) => _MethodOwner.NotifyColleaguesOfValueChanged(s, e, _MessageKey, _PropertyName);
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(_sender.Target);
System.ComponentModel.PropertyDescriptor myProperty = properties.Find(PropertyName, false);
myProperty.AddValueChanged(_sender.Target, handler);
}
}
internal void NotifyColleaguesOfValueChanged(object sender, EventArgs e, string key, string PropertyName)
{
object message = sender.GetType().GetProperty(PropertyName).GetValue(sender, null);
List<WeakPropertyDescriptor> wr;
if (_registeredListners.TryGetValue(key, out wr))
{
foreach (WeakPropertyDescriptor item in wr)
{
if (item._sender.IsAlive)
{
PropertyInfo MyProperty = item._sender.Target.GetType().GetProperty(item._PropertyName, BindingFlags.Public | BindingFlags.Instance);
if (message != MyProperty.GetValue(item._sender.Target, null))
{
if (null != MyProperty && MyProperty.CanWrite)
{
MyProperty.SetValue(item._sender.Target, message, null);
}
}
}
else
{
}
}
}
}
private void RemoveSourceFromValueChangedEventManager(object source)
{
Assembly assembly = Assembly.GetAssembly(typeof(FrameworkElement));
Type type = assembly.GetType("MS.Internal.Data.ValueChangedEventManager");
PropertyInfo propertyInfo = type.GetProperty("CurrentManager", BindingFlags.NonPublic | BindingFlags.Static);
MethodInfo currentManagerGetter = propertyInfo.GetGetMethod(true);
object manager = currentManagerGetter.Invoke(null, null);
MethodInfo remove = type.GetMethod("Remove", BindingFlags.NonPublic | BindingFlags.Instance);
remove.Invoke(manager, new object[] { source });
FieldInfo valueChangedHandlersInfo = typeof(PropertyDescriptor).GetField("valueChangedHandlers", BindingFlags.Instance | BindingFlags.NonPublic);
PropertyDescriptorCollection pdc = TypeDescriptor.GetProperties(source);
foreach (PropertyDescriptor pd in pdc)
{
Hashtable changeHandlers = (Hashtable)valueChangedHandlersInfo.GetValue(pd);
if (changeHandlers != null)
{
changeHandlers.Remove(source);
}
}
}
private void RegisterProperty(string _MessageKey, object sender, string PropertyName)
{
WeakPropertyDescriptor WeakPropertyReferance = new WeakPropertyDescriptor(this, sender, PropertyName, _MessageKey);
List<WeakPropertyDescriptor> wr;
if (_registeredListners.TryGetValue(_MessageKey, out wr))
{
if (wr != null)
{
wr.Add(WeakPropertyReferance);
}
}
else
{
wr = new List<WeakPropertyDescriptor>();
wr.Add(WeakPropertyReferance);
_registeredListners[_MessageKey] = wr;
}
}
public void Register(object view)
{
foreach (var mi in view.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public))
{
foreach (var att in mi.GetCustomAttributes(typeof(PropertyMediatorAttribute)))
{
var mha = (PropertyMediatorAttribute)att;
RegisterProperty(mha.MessageKey, view, mi.Name);
}
}
}
public void UnRegister(object view)
{
foreach (var mi in view.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public))
{
foreach (var att in mi.GetCustomAttributes(typeof(PropertyMediatorAttribute)))
{
var mha = (PropertyMediatorAttribute)att;
RemoveSourceFromValueChangedEventManager(view);
}
}
}
}
The usage is rather simple:
public class A : NotifierBase
{
public A()
{
PropertyMediator.Instance.Register(this);
}
private string m_Name = "test";
[PropertyMediatorAttribute("MyProp")]
public string Name
{
get { return m_Name; }
set
{
SetProperty(ref m_Name, value);
}
}
~A()
{
PropertyMediator.Instance.UnRegister(this);
}
}
|
|
|
|
|
Can you also show me the source for NotifierBase? I'll give it a shot then.
If the brain were so simple we could understand it, we would be so simple we couldn't. — Lyall Watson
|
|
|
|
|
It's basically just a helper that saves me some typing:
public abstract class NotifierBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (Equals(storage, value))
{
return false;
}
storage = value;
this.OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
|
|
|
|
|
Kenneth Haugland wrote: it does work but it won't allow the connected classes to be garbage collected Do you want connected classes to be able to be GC'ed individually or is it enough that they can be GC'ed once you're done with all of them?
If the brain were so simple we could understand it, we would be so simple we couldn't. — Lyall Watson
|
|
|
|
|
I have to allow them to be GB individually, as I might exchange one of the classes with a new instance.
|
|
|
|
|
I was able to make it work now:
internal class WeakPropertyDescriptor
{
public PropertyMediator _MethodOwner;
public WeakReference _sender;
public string _PropertyName;
public string _MessageKey;
public EventHandler<EventArgs> handler;
private Type constructedWEMType;
public WeakPropertyDescriptor(PropertyMediator MethodOwner, Object sender, string PropertyName, string MessageKey)
{
_MethodOwner = MethodOwner;
_sender = new WeakReference(sender);
_PropertyName = PropertyName;
_MessageKey = MessageKey;
handler = new EventHandler<EventArgs>(WeakPropertyDescriptor_PropertyChanged);
Type unboundWEMType = typeof(WeakEventManager<,>);
Type[] typeArgs = { _sender.Target.GetType(), typeof(EventArgs) };
constructedWEMType = unboundWEMType.MakeGenericType(typeArgs);
MethodInfo addHandlerMethod = constructedWEMType.GetMethod("AddHandler");
addHandlerMethod.Invoke(null, new object[] {_sender.Target , "PropertyChanged" , handler});
}
private void WeakPropertyDescriptor_PropertyChanged(object sender, EventArgs e)
{
PropertyChangedEventArgs arg = (PropertyChangedEventArgs)e;
if (arg.PropertyName == _PropertyName)
_MethodOwner.NotifyColleaguesOfValueChanged(_sender.Target, e, _MessageKey, _PropertyName);
}
public void RemoveHandler()
{
MethodInfo removeHandlerMethod = constructedWEMType.GetMethod("RemoveHandler");
removeHandlerMethod.Invoke(null, new object[] { _sender.Target, "PropertyChanged", handler });
}
}
modified 25-Jan-16 4:53am.
|
|
|
|
|
To be honest, given what you're trying to do, I would look to use RX to observe property changes. In fact, that's exactly what I have done for some of my clients.
This space for rent
|
|
|
|
|
|
I tend to use a variation of code that builds on something like this[^].
This space for rent
|
|
|
|
|
|
Thank you, Kenneth! I'll take a look at it.
If the brain were so simple we could understand it, we would be so simple we couldn't. — Lyall Watson
|
|
|
|
|
when i click a button just like i click a "Category" it auto generate all the category values button.
|
|
|
|
|
It would help to know what UI you are building for...
Have a collection of categories in the code behind
Instead of buttons use a list control (listbox with a button as the item content) and bind the category collection to the list control (DataSource or ItemSSource).
Never underestimate the power of human stupidity
RAH
|
|
|
|
|
it is also an perfect but i want to build and application to touch screen.
|
|
|
|
|
Touch screen does not dictate the structure. You may be interested in some of these articles[^]
Never underestimate the power of human stupidity
RAH
|
|
|
|
|
the above c sharp code will send client desktop images to server . it works for single client . we want to implement this for multiple client. please provide help to implement it.
SERVER code:-
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Runtime.Remoting;
using System.Linq;
using System.Text;
using System.Net .Sockets ;
using System.Windows.Forms;
using System.Threading ;
using System.Runtime.Serialization.Formatters.Binary;
using System.Net;
namespace simpleserver
{
public partial class Form2 : Form
{
private readonly int port;
private TcpClient client;
private TcpListener server;
private NetworkStream mainstream;
private readonly Thread Listening;
private readonly Thread Getimg;
public Form2(int Port)
{
port = Port;
client = new TcpClient();
Listening = new Thread(StartListening);
Getimg = new Thread(ReceiveImage);
InitializeComponent();
}
private void StartListening()
{
while (!client.Connected)
{
server.Start();
client = server.AcceptTcpClient();
}
Getimg.Start();
}
private void stop()
{
server.Stop();
client = null;
if (Listening .IsAlive )Listening .Abort ();
if ( Getimg .IsAlive )Getimg .Abort ();
}
private void ReceiveImage()
{
BinaryFormatter binformatter = new BinaryFormatter();
while (client.Connected)
{
mainstream = client.GetStream();
pictureBox1.Image =(Image ) binformatter.Deserialize(mainstream);
}
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
server = new TcpListener(IPAddress .Any ,port );
Listening .Start ();
}
}
}
CLIENT CODE:-
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters.Binary;
namespace sampleclient
{
public partial class Form1 : Form
{
private readonly TcpClient client = new TcpClient();
private NetworkStream mainStream;
private int portNumber;
private static Image GetDesktop()
{
Rectangle bounds = Screen.PrimaryScreen.Bounds;
Bitmap screenshot = new Bitmap(bounds .Width ,bounds .Height,PixelFormat .Format32bppArgb );
Graphics g = Graphics.FromImage(screenshot);
g.CopyFromScreen(bounds.X, bounds.Y, 0, 0, bounds.Size, CopyPixelOperation.SourceCopy);
return screenshot;
}
private void SendDesktop()
{
BinaryFormatter binformatter = new BinaryFormatter ();
mainStream = client.GetStream();
binformatter.Serialize (mainStream, GetDesktop());
}
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
portNumber = int.Parse(textBox2.Text);
try
{
client.Connect(textBox1.Text, portNumber);
MessageBox.Show("connected success");
timer1.Start();
}
catch (Exception)
{
MessageBox.Show("fail");
}
}
private void timer1_Tick(object sender, EventArgs e)
{
SendDesktop ();
}
}
}
modified 23-Jan-16 12:12pm.
|
|
|
|
|
Apart from that being terrible code - VS default names for everything, commented out blocks, assumptions that users never type mistakes, ignoring exception detail when you do catch them, and so forth - we have no idea what you mean by "make it work for multiple clients", or what you problem with doing it yourself is.
And when you add that we aren't here to do your job for you I think it's very unlikely that you will get what you want with this question.
Instead, sit down and work out exactly what you are trying to do, and work out what you need to implement in order to do it. Then make a list of what you do and don;t know how to do, and implement the stuff you do.
For the stuff you don't start with google, and ask specific questions when you can't find what you need, or don't understand whatyou find.
But just saving "provide help to implement it" isn't going to get you very far...
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
|
|
|
|
|
First of all, have you considered using
code pre tags when posting code? It makes it much easier to read.
Second, what have you attempted so far?
"I've seen more information on a frickin' sticky note!" - Dave Kreskowiak
|
|
|
|
|